1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
* vim: set ts=8 sw=4 et tw=78:
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/. */
8
#ifndef ObjectImpl_h___
9
#define ObjectImpl_h___
11
#include "mozilla/Assertions.h"
12
#include "mozilla/StandardInteger.h"
14
#include "jsfriendapi.h"
18
#include "gc/Barrier.h"
19
#include "vm/NumericConversions.h"
20
#include "vm/String.h"
27
class AutoPropDescArrayRooter;
29
static inline PropertyOp
30
CastAsPropertyOp(JSObject *object)
32
return JS_DATA_TO_FUNC_PTR(PropertyOp, object);
35
static inline StrictPropertyOp
36
CastAsStrictPropertyOp(JSObject *object)
38
return JS_DATA_TO_FUNC_PTR(StrictPropertyOp, object);
42
* Properties are stored differently depending on the type of the key. If the
43
* key is an unsigned 32-bit integer (i.e. an index), we call such properties
44
* "elements" and store them in one of a number of forms (optimized for dense
45
* property storage, typed array data, and so on). All other properties are
46
* stored using shapes and shape trees. Keys for these properties are either
47
* PropertyNames (that is, atomized strings whose contents are not unsigned
48
* 32-bit integers) or SpecialIds (object values for E4X and a couple other
49
* things, see jsid for details); the union of these types, used in individual
50
* shapes, is PropertyId.
58
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SPECIAL(id));
59
return JSID_IS_STRING(id);
61
bool isSpecial() const {
62
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SPECIAL(id));
67
*this = PropertyId(SpecialId());
69
explicit PropertyId(PropertyName *name)
70
: id(NON_INTEGER_ATOM_TO_JSID(name))
72
explicit PropertyId(const SpecialId &sid)
73
: id(SPECIALID_TO_JSID(sid))
76
PropertyName * asName() const {
77
return JSID_TO_STRING(id)->asAtom().asPropertyName();
79
SpecialId asSpecial() const {
80
return JSID_TO_SPECIALID(id);
82
const jsid &asId() const {
89
bool operator==(const PropertyId &rhs) const { return id == rhs.id; }
90
bool operator!=(const PropertyId &rhs) const { return id != rhs.id; }
94
* A representation of ECMA-262 ed. 5's internal Property Descriptor data
100
* Original object from which this descriptor derives, passed through for
101
* the benefit of proxies. FIXME: Remove this when direct proxies happen.
105
Value value_, get_, set_;
107
/* Property descriptor boolean fields. */
110
/* Bits indicating which values are set. */
114
bool hasWritable_ : 1;
115
bool hasEnumerable_ : 1;
116
bool hasConfigurable_ : 1;
118
/* Or maybe this represents a property's absence, and it's undefined. */
119
bool isUndefined_ : 1;
121
PropDesc(const Value &v)
122
: pd_(UndefinedValue()),
124
get_(UndefinedValue()), set_(UndefinedValue()),
126
hasGet_(false), hasSet_(false),
127
hasValue_(true), hasWritable_(false), hasEnumerable_(false), hasConfigurable_(false),
133
friend class AutoPropDescArrayRooter;
134
friend void JS::AutoGCRooter::trace(JSTracer *trc);
136
enum Enumerability { Enumerable = true, NonEnumerable = false };
137
enum Configurability { Configurable = true, NonConfigurable = false };
138
enum Writability { Writable = true, NonWritable = false };
142
static PropDesc undefined() { return PropDesc(); }
143
static PropDesc valueOnly(const Value &v) { return PropDesc(v); }
145
PropDesc(const Value &v, Writability writable,
146
Enumerability enumerable, Configurability configurable)
147
: pd_(UndefinedValue()),
149
get_(UndefinedValue()), set_(UndefinedValue()),
150
attrs((writable ? 0 : JSPROP_READONLY) |
151
(enumerable ? JSPROP_ENUMERATE : 0) |
152
(configurable ? 0 : JSPROP_PERMANENT)),
153
hasGet_(false), hasSet_(false),
154
hasValue_(true), hasWritable_(true), hasEnumerable_(true), hasConfigurable_(true),
158
inline PropDesc(const Value &getter, const Value &setter,
159
Enumerability enumerable, Configurability configurable);
162
* 8.10.5 ToPropertyDescriptor(Obj)
164
* If checkAccessors is false, skip steps 7.b and 8.b, which throw a
165
* TypeError if .get or .set is neither a callable object nor undefined.
167
* (DebuggerObject_defineProperty uses this: the .get and .set properties
168
* are expected to be Debugger.Object wrappers of functions, which are not
169
* themselves callable.)
171
bool initialize(JSContext* cx, const Value &v, bool checkAccessors = true);
174
* 8.10.4 FromPropertyDescriptor(Desc)
176
* initFromPropertyDescriptor sets pd to undefined and populates all the
177
* other fields of this PropDesc from desc.
179
* makeObject populates pd based on the other fields of *this, creating a
180
* new property descriptor JSObject and defining properties on it.
182
void initFromPropertyDescriptor(const PropertyDescriptor &desc);
183
bool makeObject(JSContext *cx);
185
void setUndefined() { isUndefined_ = true; }
187
bool isUndefined() const { return isUndefined_; }
189
bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; }
190
bool hasSet() const { MOZ_ASSERT(!isUndefined()); return hasSet_; }
191
bool hasValue() const { MOZ_ASSERT(!isUndefined()); return hasValue_; }
192
bool hasWritable() const { MOZ_ASSERT(!isUndefined()); return hasWritable_; }
193
bool hasEnumerable() const { MOZ_ASSERT(!isUndefined()); return hasEnumerable_; }
194
bool hasConfigurable() const { MOZ_ASSERT(!isUndefined()); return hasConfigurable_; }
196
Value pd() const { MOZ_ASSERT(!isUndefined()); return pd_; }
197
void clearPd() { pd_ = UndefinedValue(); }
199
uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; }
201
/* 8.10.1 IsAccessorDescriptor(desc) */
202
bool isAccessorDescriptor() const {
203
return !isUndefined() && (hasGet() || hasSet());
206
/* 8.10.2 IsDataDescriptor(desc) */
207
bool isDataDescriptor() const {
208
return !isUndefined() && (hasValue() || hasWritable());
211
/* 8.10.3 IsGenericDescriptor(desc) */
212
bool isGenericDescriptor() const {
213
return !isUndefined() && !isAccessorDescriptor() && !isDataDescriptor();
216
bool configurable() const {
217
MOZ_ASSERT(!isUndefined());
218
MOZ_ASSERT(hasConfigurable());
219
return (attrs & JSPROP_PERMANENT) == 0;
222
bool enumerable() const {
223
MOZ_ASSERT(!isUndefined());
224
MOZ_ASSERT(hasEnumerable());
225
return (attrs & JSPROP_ENUMERATE) != 0;
228
bool writable() const {
229
MOZ_ASSERT(!isUndefined());
230
MOZ_ASSERT(hasWritable());
231
return (attrs & JSPROP_READONLY) == 0;
234
HandleValue value() const {
235
MOZ_ASSERT(hasValue());
236
return HandleValue::fromMarkedLocation(&value_);
239
JSObject * getterObject() const {
240
MOZ_ASSERT(!isUndefined());
241
MOZ_ASSERT(hasGet());
242
return get_.isUndefined() ? NULL : &get_.toObject();
244
JSObject * setterObject() const {
245
MOZ_ASSERT(!isUndefined());
246
MOZ_ASSERT(hasSet());
247
return set_.isUndefined() ? NULL : &set_.toObject();
250
HandleValue getterValue() const {
251
MOZ_ASSERT(!isUndefined());
252
MOZ_ASSERT(hasGet());
253
return HandleValue::fromMarkedLocation(&get_);
255
HandleValue setterValue() const {
256
MOZ_ASSERT(!isUndefined());
257
MOZ_ASSERT(hasSet());
258
return HandleValue::fromMarkedLocation(&set_);
262
* Unfortunately the values produced by these methods are used such that
263
* we can't assert anything here. :-(
265
PropertyOp getter() const {
266
return CastAsPropertyOp(get_.isUndefined() ? NULL : &get_.toObject());
268
StrictPropertyOp setter() const {
269
return CastAsStrictPropertyOp(set_.isUndefined() ? NULL : &set_.toObject());
273
* Throw a TypeError if a getter/setter is present and is neither callable
274
* nor undefined. These methods do exactly the type checks that are skipped
275
* by passing false as the checkAccessors parameter of initialize.
277
bool checkGetter(JSContext *cx);
278
bool checkSetter(JSContext *cx);
280
bool unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj,
281
PropDesc *unwrapped) const;
283
bool wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId,
284
PropDesc *wrappedDesc) const;
286
class AutoRooter : private AutoGCRooter
289
explicit AutoRooter(JSContext *cx, PropDesc *pd_
290
JS_GUARD_OBJECT_NOTIFIER_PARAM)
291
: AutoGCRooter(cx, PROPDESC), pd(pd_), skip(cx, pd_)
293
JS_GUARD_OBJECT_NOTIFIER_INIT;
296
friend void AutoGCRooter::trace(JSTracer *trc);
301
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
305
class DenseElementsHeader;
306
class SparseElementsHeader;
307
class Uint8ElementsHeader;
308
class Int8ElementsHeader;
309
class Uint16ElementsHeader;
310
class Int16ElementsHeader;
311
class Uint32ElementsHeader;
312
class Int32ElementsHeader;
313
class Uint8ClampedElementsHeader;
314
class Float32ElementsHeader;
315
class Float64ElementsHeader;
316
class Uint8ClampedElementsHeader;
317
class ArrayBufferElementsHeader;
325
/* These typed element types must remain contiguous. */
332
Uint8ClampedElements,
341
uint32_t length; /* Array length, ArrayBuffer length, typed array length */
345
friend class DenseElementsHeader;
346
uint32_t initializedLength;
350
friend class SparseElementsHeader;
355
void staticAsserts() {
356
MOZ_STATIC_ASSERT(sizeof(ElementsHeader) == ValuesPerHeader * sizeof(Value),
357
"Elements size and values-per-Elements mismatch");
361
ElementsKind kind() const {
362
MOZ_ASSERT(type <= ArrayBufferElements);
363
return ElementsKind(type);
366
inline bool isDenseElements() const { return kind() == DenseElements; }
367
inline bool isSparseElements() const { return kind() == SparseElements; }
368
inline bool isArrayBufferElements() const { return kind() == ArrayBufferElements; }
369
inline bool isUint8Elements() const { return kind() == Uint8Elements; }
370
inline bool isInt8Elements() const { return kind() == Int8Elements; }
371
inline bool isUint16Elements() const { return kind() == Uint16Elements; }
372
inline bool isInt16Elements() const { return kind() == Int16Elements; }
373
inline bool isUint32Elements() const { return kind() == Uint32Elements; }
374
inline bool isInt32Elements() const { return kind() == Int32Elements; }
375
inline bool isUint8ClampedElements() const { return kind() == Uint8ClampedElements; }
376
inline bool isFloat32Elements() const { return kind() == Float32Elements; }
377
inline bool isFloat64Elements() const { return kind() == Float64Elements; }
379
inline DenseElementsHeader & asDenseElements();
380
inline SparseElementsHeader & asSparseElements();
381
inline ArrayBufferElementsHeader & asArrayBufferElements();
382
inline Uint8ElementsHeader & asUint8Elements();
383
inline Int8ElementsHeader & asInt8Elements();
384
inline Uint16ElementsHeader & asUint16Elements();
385
inline Int16ElementsHeader & asInt16Elements();
386
inline Uint32ElementsHeader & asUint32Elements();
387
inline Int32ElementsHeader & asInt32Elements();
388
inline Uint8ClampedElementsHeader & asUint8ClampedElements();
389
inline Float32ElementsHeader & asFloat32Elements();
390
inline Float64ElementsHeader & asFloat64Elements();
392
static ElementsHeader * fromElements(HeapSlot *elems) {
393
return reinterpret_cast<ElementsHeader *>(uintptr_t(elems) - sizeof(ElementsHeader));
396
static const size_t ValuesPerHeader = 2;
399
class DenseElementsHeader : public ElementsHeader
402
uint32_t capacity() const {
403
MOZ_ASSERT(ElementsHeader::isDenseElements());
404
return dense.capacity;
407
uint32_t initializedLength() const {
408
MOZ_ASSERT(ElementsHeader::isDenseElements());
409
return dense.initializedLength;
412
uint32_t length() const {
413
MOZ_ASSERT(ElementsHeader::isDenseElements());
414
return ElementsHeader::length;
417
bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
418
unsigned resolveFlags, PropDesc *desc);
420
bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
421
const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
424
bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
425
uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
428
inline bool isDenseElements() const MOZ_DELETE;
429
inline DenseElementsHeader & asDenseElements() MOZ_DELETE;
431
DenseElementsHeader(const DenseElementsHeader &other) MOZ_DELETE;
432
void operator=(const DenseElementsHeader &other) MOZ_DELETE;
435
class SparseElementsHeader : public ElementsHeader
439
MOZ_ASSERT(ElementsHeader::isSparseElements());
443
uint32_t length() const {
444
MOZ_ASSERT(ElementsHeader::isSparseElements());
445
return ElementsHeader::length;
448
bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
449
unsigned resolveFlags, PropDesc *desc);
451
bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
452
const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
455
bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
456
uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
459
inline bool isSparseElements() const MOZ_DELETE;
460
inline SparseElementsHeader & asSparseElements() MOZ_DELETE;
462
SparseElementsHeader(const SparseElementsHeader &other) MOZ_DELETE;
463
void operator=(const SparseElementsHeader &other) MOZ_DELETE;
466
extern uint32_t JS_FASTCALL
467
ClampDoubleToUint8(const double x);
469
struct uint8_clamped {
473
uint8_clamped(const uint8_clamped& other) : val(other.val) { }
475
// invoke our assignment helpers for constructor conversion
476
uint8_clamped(uint8_t x) { *this = x; }
477
uint8_clamped(uint16_t x) { *this = x; }
478
uint8_clamped(uint32_t x) { *this = x; }
479
uint8_clamped(int8_t x) { *this = x; }
480
uint8_clamped(int16_t x) { *this = x; }
481
uint8_clamped(int32_t x) { *this = x; }
482
uint8_clamped(double x) { *this = x; }
484
uint8_clamped& operator=(const uint8_clamped& x) {
489
uint8_clamped& operator=(uint8_t x) {
494
uint8_clamped& operator=(uint16_t x) {
495
val = (x > 255) ? 255 : uint8_t(x);
499
uint8_clamped& operator=(uint32_t x) {
500
val = (x > 255) ? 255 : uint8_t(x);
504
uint8_clamped& operator=(int8_t x) {
505
val = (x >= 0) ? uint8_t(x) : 0;
509
uint8_clamped& operator=(int16_t x) {
518
uint8_clamped& operator=(int32_t x) {
527
uint8_clamped& operator=(const double x) {
528
val = uint8_t(ClampDoubleToUint8(x));
532
operator uint8_t() const {
536
void staticAsserts() {
537
MOZ_STATIC_ASSERT(sizeof(uint8_clamped) == 1,
538
"uint8_clamped must be layout-compatible with uint8_t");
542
/* Note that we can't use std::numeric_limits here due to uint8_clamped. */
543
template<typename T> static inline const bool TypeIsFloatingPoint() { return false; }
544
template<> inline const bool TypeIsFloatingPoint<float>() { return true; }
545
template<> inline const bool TypeIsFloatingPoint<double>() { return true; }
547
template<typename T> static inline const bool TypeIsUnsigned() { return false; }
548
template<> inline const bool TypeIsUnsigned<uint8_t>() { return true; }
549
template<> inline const bool TypeIsUnsigned<uint16_t>() { return true; }
550
template<> inline const bool TypeIsUnsigned<uint32_t>() { return true; }
552
template <typename T>
553
class TypedElementsHeader : public ElementsHeader
555
T getElement(uint32_t index) {
556
MOZ_ASSERT(index < length());
557
return reinterpret_cast<T *>(this + 1)[index];
560
inline void assign(uint32_t index, double d);
562
void setElement(uint32_t index, T value) {
563
MOZ_ASSERT(index < length());
564
reinterpret_cast<T *>(this + 1)[index] = value;
568
uint32_t length() const {
569
MOZ_ASSERT(Uint8Elements <= kind());
570
MOZ_ASSERT(kind() <= Float64Elements);
571
return ElementsHeader::length;
574
bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
575
unsigned resolveFlags, PropDesc *desc);
577
bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
578
const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
581
bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
582
uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
585
TypedElementsHeader(const TypedElementsHeader &other) MOZ_DELETE;
586
void operator=(const TypedElementsHeader &other) MOZ_DELETE;
589
template<typename T> inline void
590
TypedElementsHeader<T>::assign(uint32_t index, double d)
592
MOZ_NOT_REACHED("didn't specialize for this element type");
595
template<> inline void
596
TypedElementsHeader<uint8_clamped>::assign(uint32_t index, double d)
598
double i = ToInteger(d);
604
setElement(index, uint8_clamped(u));
607
template<> inline void
608
TypedElementsHeader<uint8_t>::assign(uint32_t index, double d)
610
setElement(index, uint8_t(ToUint32(d)));
613
template<> inline void
614
TypedElementsHeader<int8_t>::assign(uint32_t index, double d)
616
/* FIXME: Casting out-of-range signed integers has undefined behavior! */
617
setElement(index, int8_t(ToInt32(d)));
620
template<> inline void
621
TypedElementsHeader<uint16_t>::assign(uint32_t index, double d)
623
setElement(index, uint16_t(ToUint32(d)));
626
template<> inline void
627
TypedElementsHeader<int16_t>::assign(uint32_t index, double d)
629
/* FIXME: Casting out-of-range signed integers has undefined behavior! */
630
setElement(index, int16_t(ToInt32(d)));
633
template<> inline void
634
TypedElementsHeader<uint32_t>::assign(uint32_t index, double d)
636
setElement(index, ToUint32(d));
639
template<> inline void
640
TypedElementsHeader<int32_t>::assign(uint32_t index, double d)
642
/* FIXME: Casting out-of-range signed integers has undefined behavior! */
643
setElement(index, int32_t(ToInt32(d)));
646
template<> inline void
647
TypedElementsHeader<float>::assign(uint32_t index, double d)
649
setElement(index, float(d));
652
template<> inline void
653
TypedElementsHeader<double>::assign(uint32_t index, double d)
655
setElement(index, d);
658
class Uint8ElementsHeader : public TypedElementsHeader<uint8_t>
661
inline bool isUint8Elements() const MOZ_DELETE;
662
inline Uint8ElementsHeader & asUint8Elements() MOZ_DELETE;
663
Uint8ElementsHeader(const Uint8ElementsHeader &other) MOZ_DELETE;
664
void operator=(const Uint8ElementsHeader &other) MOZ_DELETE;
666
class Int8ElementsHeader : public TypedElementsHeader<int8_t>
669
bool isInt8Elements() const MOZ_DELETE;
670
Int8ElementsHeader & asInt8Elements() MOZ_DELETE;
671
Int8ElementsHeader(const Int8ElementsHeader &other) MOZ_DELETE;
672
void operator=(const Int8ElementsHeader &other) MOZ_DELETE;
674
class Uint16ElementsHeader : public TypedElementsHeader<uint16_t>
677
bool isUint16Elements() const MOZ_DELETE;
678
Uint16ElementsHeader & asUint16Elements() MOZ_DELETE;
679
Uint16ElementsHeader(const Uint16ElementsHeader &other) MOZ_DELETE;
680
void operator=(const Uint16ElementsHeader &other) MOZ_DELETE;
682
class Int16ElementsHeader : public TypedElementsHeader<int16_t>
685
bool isInt16Elements() const MOZ_DELETE;
686
Int16ElementsHeader & asInt16Elements() MOZ_DELETE;
687
Int16ElementsHeader(const Int16ElementsHeader &other) MOZ_DELETE;
688
void operator=(const Int16ElementsHeader &other) MOZ_DELETE;
690
class Uint32ElementsHeader : public TypedElementsHeader<uint32_t>
693
bool isUint32Elements() const MOZ_DELETE;
694
Uint32ElementsHeader & asUint32Elements() MOZ_DELETE;
695
Uint32ElementsHeader(const Uint32ElementsHeader &other) MOZ_DELETE;
696
void operator=(const Uint32ElementsHeader &other) MOZ_DELETE;
698
class Int32ElementsHeader : public TypedElementsHeader<int32_t>
701
bool isInt32Elements() const MOZ_DELETE;
702
Int32ElementsHeader & asInt32Elements() MOZ_DELETE;
703
Int32ElementsHeader(const Int32ElementsHeader &other) MOZ_DELETE;
704
void operator=(const Int32ElementsHeader &other) MOZ_DELETE;
706
class Float32ElementsHeader : public TypedElementsHeader<float>
709
bool isFloat32Elements() const MOZ_DELETE;
710
Float32ElementsHeader & asFloat32Elements() MOZ_DELETE;
711
Float32ElementsHeader(const Float32ElementsHeader &other) MOZ_DELETE;
712
void operator=(const Float32ElementsHeader &other) MOZ_DELETE;
714
class Float64ElementsHeader : public TypedElementsHeader<double>
717
bool isFloat64Elements() const MOZ_DELETE;
718
Float64ElementsHeader & asFloat64Elements() MOZ_DELETE;
719
Float64ElementsHeader(const Float64ElementsHeader &other) MOZ_DELETE;
720
void operator=(const Float64ElementsHeader &other) MOZ_DELETE;
723
class Uint8ClampedElementsHeader : public TypedElementsHeader<uint8_clamped>
726
inline bool isUint8Clamped() const MOZ_DELETE;
727
inline Uint8ClampedElementsHeader & asUint8ClampedElements() MOZ_DELETE;
728
Uint8ClampedElementsHeader(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
729
void operator=(const Uint8ClampedElementsHeader &other) MOZ_DELETE;
732
class ArrayBufferElementsHeader : public ElementsHeader
735
bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
736
unsigned resolveFlags, PropDesc *desc);
738
bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
739
const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
742
bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
743
uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
746
inline bool isArrayBufferElements() const MOZ_DELETE;
747
inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE;
749
ArrayBufferElementsHeader(const ArrayBufferElementsHeader &other) MOZ_DELETE;
750
void operator=(const ArrayBufferElementsHeader &other) MOZ_DELETE;
753
inline DenseElementsHeader &
754
ElementsHeader::asDenseElements()
756
MOZ_ASSERT(isDenseElements());
757
return *static_cast<DenseElementsHeader *>(this);
760
inline SparseElementsHeader &
761
ElementsHeader::asSparseElements()
763
MOZ_ASSERT(isSparseElements());
764
return *static_cast<SparseElementsHeader *>(this);
767
inline Uint8ElementsHeader &
768
ElementsHeader::asUint8Elements()
770
MOZ_ASSERT(isUint8Elements());
771
return *static_cast<Uint8ElementsHeader *>(this);
774
inline Int8ElementsHeader &
775
ElementsHeader::asInt8Elements()
777
MOZ_ASSERT(isInt8Elements());
778
return *static_cast<Int8ElementsHeader *>(this);
781
inline Uint16ElementsHeader &
782
ElementsHeader::asUint16Elements()
784
MOZ_ASSERT(isUint16Elements());
785
return *static_cast<Uint16ElementsHeader *>(this);
788
inline Int16ElementsHeader &
789
ElementsHeader::asInt16Elements()
791
MOZ_ASSERT(isInt16Elements());
792
return *static_cast<Int16ElementsHeader *>(this);
795
inline Uint32ElementsHeader &
796
ElementsHeader::asUint32Elements()
798
MOZ_ASSERT(isUint32Elements());
799
return *static_cast<Uint32ElementsHeader *>(this);
802
inline Int32ElementsHeader &
803
ElementsHeader::asInt32Elements()
805
MOZ_ASSERT(isInt32Elements());
806
return *static_cast<Int32ElementsHeader *>(this);
809
inline Uint8ClampedElementsHeader &
810
ElementsHeader::asUint8ClampedElements()
812
MOZ_ASSERT(isUint8ClampedElements());
813
return *static_cast<Uint8ClampedElementsHeader *>(this);
816
inline Float32ElementsHeader &
817
ElementsHeader::asFloat32Elements()
819
MOZ_ASSERT(isFloat32Elements());
820
return *static_cast<Float32ElementsHeader *>(this);
823
inline Float64ElementsHeader &
824
ElementsHeader::asFloat64Elements()
826
MOZ_ASSERT(isFloat64Elements());
827
return *static_cast<Float64ElementsHeader *>(this);
830
inline ArrayBufferElementsHeader &
831
ElementsHeader::asArrayBufferElements()
833
MOZ_ASSERT(isArrayBufferElements());
834
return *static_cast<ArrayBufferElementsHeader *>(this);
838
* Header structure for object element arrays. This structure is immediately
839
* followed by an array of elements, with the elements member in an object
840
* pointing to the beginning of that array (the end of this structure).
841
* See below for usage of this structure.
843
class ArrayBufferObject;
846
friend struct ::JSObject;
847
friend class ObjectImpl;
848
friend class ArrayBufferObject;
850
/* Number of allocated slots. */
854
* Number of initialized elements. This is <= the capacity, and for arrays
855
* is <= the length. Memory for elements above the initialized length is
856
* uninitialized, but values between the initialized length and the proper
857
* length are conceptually holes.
859
uint32_t initializedLength;
861
/* 'length' property of array objects, unused for other objects. */
864
/* :XXX: bug 586842 store state about sparse slots. */
867
void staticAsserts() {
868
MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
869
"Elements size and values-per-Elements mismatch");
874
ObjectElements(uint32_t capacity, uint32_t length)
875
: capacity(capacity), initializedLength(0), length(length)
878
HeapSlot *elements() { return (HeapSlot *)(uintptr_t(this) + sizeof(ObjectElements)); }
879
static ObjectElements * fromElements(HeapSlot *elems) {
880
return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements));
883
static int offsetOfCapacity() {
884
return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements);
886
static int offsetOfInitializedLength() {
887
return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements);
889
static int offsetOfLength() {
890
return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements);
893
static const size_t VALUES_PER_HEADER = 2;
896
/* Shared singleton for objects with no elements. */
897
extern HeapSlot *emptyObjectElements;
904
class NewObjectCache;
907
ObjectValue(ObjectImpl &obj);
910
* ObjectImpl specifies the internal implementation of an object. (In contrast
911
* JSObject specifies an "external" interface, at the conceptual level of that
912
* exposed in ECMAScript.)
914
* The |shape_| member stores the shape of the object, which includes the
915
* object's class and the layout of all its properties.
917
* The type member stores the type of the object, which contains its prototype
918
* object and the possible types of its properties.
920
* The rest of the object stores its named properties and indexed elements.
921
* These are stored separately from one another. Objects are followed by an
922
* variable-sized array of values for inline storage, which may be used by
923
* either properties of native objects (fixed slots) or by elements.
925
* Two native objects with the same shape are guaranteed to have the same
926
* number of fixed slots.
928
* Named property storage can be split between fixed slots and a dynamically
929
* allocated array (the slots member). For an object with N fixed slots, shapes
930
* with slots [0..N-1] are stored in the fixed slots, and the remainder are
931
* stored in the dynamic array. If all properties fit in the fixed slots, the
932
* 'slots' member is NULL.
934
* Elements are indexed via the 'elements' member. This member can point to
935
* either the shared emptyObjectElements singleton, into the inline value array
936
* (the address of the third value, to leave room for a ObjectElements header;
937
* in this case numFixedSlots() is zero) or to a dynamically allocated array.
939
* Only certain combinations of properties and elements storage are currently
940
* possible. This will be changing soon :XXX: bug 586842.
942
* - For objects other than arrays and typed arrays, the elements are empty.
944
* - For 'slow' arrays, both elements and properties are used, but the
945
* elements have zero capacity --- only the length member is used.
947
* - For dense arrays, elements are used and properties are not used.
949
* - For typed array buffers, elements are used and properties are not used.
950
* The data indexed by the elements do not represent Values, but primitive
951
* unboxed integers or floating point values.
953
* The members of this class are currently protected; in the long run this will
954
* will change so that some members are private, and only certain methods that
955
* act upon them will be protected.
957
class ObjectImpl : public gc::Cell
961
* Shape of the object, encodes the layout of the object's properties and
962
* all other information about its structure. See jsscope.h.
967
* The object's type and prototype. For objects with the LAZY_TYPE flag
968
* set, this is the prototype's default 'new' type and can only be used
969
* to get that prototype.
971
HeapPtrTypeObject type_;
973
HeapSlot *slots; /* Slots for object properties. */
974
HeapSlot *elements; /* Slots for object elements. */
977
static void staticAsserts() {
978
MOZ_STATIC_ASSERT(sizeof(ObjectImpl) == sizeof(shadow::Object),
979
"shadow interface must match actual implementation");
980
MOZ_STATIC_ASSERT(sizeof(ObjectImpl) % sizeof(Value) == 0,
981
"fixed slots after an object must be aligned");
983
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
984
"shadow shape must match actual shape");
985
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
986
"shadow type must match actual type");
987
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
988
"shadow slots must match actual slots");
989
MOZ_STATIC_ASSERT(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
990
"shadow placeholder must match actual elements");
993
JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
995
friend inline Value ObjectValue(ObjectImpl &obj);
997
/* These functions are public, and they should remain public. */
1000
JSObject * getProto() const {
1001
return type_->proto;
1004
inline bool isExtensible() const;
1007
* XXX Once the property/element split of bug 586842 is complete, these
1008
* methods should move back to JSObject.
1010
inline bool isDenseArray() const;
1011
inline bool isSlowArray() const;
1012
inline bool isArray() const;
1014
inline HeapSlotArray getDenseArrayElements();
1015
inline const Value & getDenseArrayElement(uint32_t idx);
1016
inline uint32_t getDenseArrayInitializedLength();
1018
bool makeElementsSparse(JSContext *cx) {
1019
NEW_OBJECT_REPRESENTATION_ONLY();
1021
MOZ_NOT_REACHED("NYI");
1027
void checkShapeConsistency();
1029
void checkShapeConsistency() { }
1034
* Get internal pointers to the range of values starting at start and
1035
* running for length.
1037
inline void getSlotRangeUnchecked(uint32_t start, uint32_t length,
1038
HeapSlot **fixedStart, HeapSlot **fixedEnd,
1039
HeapSlot **slotsStart, HeapSlot **slotsEnd);
1040
inline void getSlotRange(uint32_t start, uint32_t length,
1041
HeapSlot **fixedStart, HeapSlot **fixedEnd,
1042
HeapSlot **slotsStart, HeapSlot **slotsEnd);
1045
friend struct GCMarker;
1046
friend struct Shape;
1047
friend class NewObjectCache;
1049
inline void invalidateSlotRange(uint32_t start, uint32_t count);
1050
inline void initializeSlotRange(uint32_t start, uint32_t count);
1053
* Initialize a flat array of slots to this object at a start slot. The
1054
* caller must ensure that are enough slots.
1056
void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
1059
* Copy a flat array of slots to this object at a start slot. Caller must
1060
* ensure there are enough slots in this object.
1062
void copySlotRange(uint32_t start, const Value *vector, uint32_t length);
1065
enum SentinelAllowed {
1066
SENTINEL_NOT_ALLOWED,
1071
* Check that slot is in range for the object's allocated slots.
1072
* If sentinelAllowed then slot may equal the slot capacity.
1074
bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
1077
/* Minimum size for dynamically allocated slots. */
1078
static const uint32_t SLOT_CAPACITY_MIN = 8;
1080
HeapSlot *fixedSlots() const {
1081
return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
1084
friend class ElementsHeader;
1085
friend class DenseElementsHeader;
1086
friend class SparseElementsHeader;
1088
enum DenseElementsResult {
1094
DenseElementsResult ensureDenseElementsInitialized(JSContext *cx, uint32_t index,
1097
NEW_OBJECT_REPRESENTATION_ONLY();
1099
MOZ_NOT_REACHED("NYI");
1104
* These functions are currently public for simplicity; in the long run
1105
* it may make sense to make at least some of them private.
1109
Shape * lastProperty() const {
1114
inline bool isNative() const;
1116
types::TypeObject *type() const {
1117
MOZ_ASSERT(!hasLazyType());
1121
uint32_t numFixedSlots() const {
1122
return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
1126
* Whether this is the only object which has its specified type. This
1127
* object will have its type constructed lazily as needed by analysis.
1129
bool hasSingletonType() const { return !!type_->singleton; }
1132
* Whether the object's type has not been constructed yet. If an object
1133
* might have a lazy type, use getType() below, otherwise type().
1135
bool hasLazyType() const { return type_->lazy(); }
1137
inline uint32_t slotSpan() const;
1139
/* Compute dynamicSlotsCount() for this object. */
1140
inline uint32_t numDynamicSlots() const;
1142
Shape * nativeLookup(JSContext *cx, jsid id);
1143
inline Shape * nativeLookup(JSContext *cx, PropertyId pid);
1144
inline Shape * nativeLookup(JSContext *cx, PropertyName *name);
1146
Shape * nativeLookupNoAllocation(jsid id);
1147
inline Shape * nativeLookupNoAllocation(PropertyId pid);
1148
inline Shape * nativeLookupNoAllocation(PropertyName *name);
1150
inline Class *getClass() const;
1151
inline JSClass *getJSClass() const;
1152
inline bool hasClass(const Class *c) const;
1153
inline const ObjectOps *getOps() const;
1156
* An object is a delegate if it is on another object's prototype or scope
1157
* chain, and therefore the delegate might be asked implicitly to get or
1158
* set a property on behalf of another object. Delegates may be accessed
1159
* directly too, as may any object, but only those objects linked after the
1160
* head of any prototype or scope chain are flagged as delegates. This
1161
* definition helps to optimize shape-based property cache invalidation
1162
* (see Purge{Scope,Proto}Chain in jsobj.cpp).
1164
inline bool isDelegate() const;
1167
* Return true if this object is a native one that has been converted from
1168
* shared-immutable prototype-rooted shape storage to dictionary-shapes in
1169
* a doubly-linked list.
1171
inline bool inDictionaryMode() const;
1173
const Value &getSlot(uint32_t slot) const {
1174
MOZ_ASSERT(slotInRange(slot));
1175
uint32_t fixed = numFixedSlots();
1177
return fixedSlots()[slot];
1178
return slots[slot - fixed];
1181
HeapSlot *getSlotAddressUnchecked(uint32_t slot) {
1182
uint32_t fixed = numFixedSlots();
1184
return fixedSlots() + slot;
1185
return slots + (slot - fixed);
1188
HeapSlot *getSlotAddress(uint32_t slot) {
1190
* This can be used to get the address of the end of the slots for the
1191
* object, which may be necessary when fetching zero-length arrays of
1192
* slots (e.g. for callObjVarArray).
1194
MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
1195
return getSlotAddressUnchecked(slot);
1198
HeapSlot &getSlotRef(uint32_t slot) {
1199
MOZ_ASSERT(slotInRange(slot));
1200
return *getSlotAddress(slot);
1203
inline HeapSlot &nativeGetSlotRef(uint32_t slot);
1204
inline const Value &nativeGetSlot(uint32_t slot) const;
1206
inline void setSlot(uint32_t slot, const Value &value);
1207
inline void initSlot(uint32_t slot, const Value &value);
1208
inline void initCrossCompartmentSlot(uint32_t slot, const js::Value &value);
1209
inline void initSlotUnchecked(uint32_t slot, const Value &value);
1211
/* For slots which are known to always be fixed, due to the way they are allocated. */
1213
HeapSlot &getFixedSlotRef(uint32_t slot) {
1214
MOZ_ASSERT(slot < numFixedSlots());
1215
return fixedSlots()[slot];
1218
const Value &getFixedSlot(uint32_t slot) const {
1219
MOZ_ASSERT(slot < numFixedSlots());
1220
return fixedSlots()[slot];
1223
inline void setFixedSlot(uint32_t slot, const Value &value);
1224
inline void initFixedSlot(uint32_t slot, const Value &value);
1227
* Get the number of dynamic slots to allocate to cover the properties in
1228
* an object with the given number of fixed slots and slot span. The slot
1229
* capacity is not stored explicitly, and the allocated size of the slot
1230
* array is kept in sync with this count.
1232
static inline uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span);
1234
/* Memory usage functions. */
1235
inline size_t sizeOfThis() const;
1237
/* Elements accessors. */
1239
ObjectElements * getElementsHeader() const {
1240
return ObjectElements::fromElements(elements);
1243
ElementsHeader & elementsHeader() const {
1244
NEW_OBJECT_REPRESENTATION_ONLY();
1245
return *ElementsHeader::fromElements(elements);
1248
inline HeapSlot *fixedElements() const {
1249
MOZ_STATIC_ASSERT(2 * sizeof(Value) == sizeof(ObjectElements),
1250
"when elements are stored inline, the first two "
1251
"slots will hold the ObjectElements header");
1252
return &fixedSlots()[2];
1255
void setFixedElements() { this->elements = fixedElements(); }
1257
inline bool hasDynamicElements() const {
1259
* Note: for objects with zero fixed slots this could potentially give
1260
* a spurious 'true' result, if the end of this object is exactly
1261
* aligned with the end of its arena and dynamic slots are allocated
1262
* immediately afterwards. Such cases cannot occur for dense arrays
1263
* (which have at least two fixed slots) and can only result in a leak.
1265
return elements != emptyObjectElements && elements != fixedElements();
1269
static inline ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
1270
static inline void readBarrier(ObjectImpl *obj);
1271
static inline void writeBarrierPre(ObjectImpl *obj);
1272
static inline void writeBarrierPost(ObjectImpl *obj, void *addr);
1273
inline void privateWriteBarrierPre(void **oldval);
1274
inline void privateWriteBarrierPost(void **pprivate);
1275
void markChildren(JSTracer *trc);
1277
/* Private data accessors. */
1279
inline void *&privateRef(uint32_t nfixed) const; /* XXX should be private, not protected! */
1281
inline bool hasPrivate() const;
1282
inline void *getPrivate() const;
1283
inline void setPrivate(void *data);
1284
inline void setPrivateGCThing(gc::Cell *cell);
1285
inline void setPrivateUnbarriered(void *data);
1286
inline void initPrivate(void *data);
1288
/* Access private data for an object with a known number of fixed slots. */
1289
inline void *getPrivate(uint32_t nfixed) const;
1292
static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
1293
HeapPtrShape *addressOfShape() { return &shape_; }
1295
static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
1296
HeapPtrTypeObject *addressOfType() { return &type_; }
1298
static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
1299
static size_t offsetOfFixedElements() {
1300
return sizeof(ObjectImpl) + sizeof(ObjectElements);
1303
static size_t getFixedSlotOffset(size_t slot) {
1304
return sizeof(ObjectImpl) + slot * sizeof(Value);
1306
static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
1307
static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
1311
ObjectValue(ObjectImpl &obj)
1314
v.setObject(*obj.asObjectPtr());
1318
inline Handle<JSObject*>
1319
Downcast(Handle<ObjectImpl*> obj)
1321
return Handle<JSObject*>::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
1325
ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj);
1327
/* Generic [[GetOwnProperty]] method. */
1329
GetOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
1332
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, PropertyId pid, unsigned resolveFlags,
1335
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<PropertyName*> name,
1336
unsigned resolveFlags, PropDesc *desc)
1338
return GetOwnProperty(cx, obj, PropertyId(name), resolveFlags, desc);
1341
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<SpecialId> sid, unsigned resolveFlags,
1344
return GetOwnProperty(cx, obj, PropertyId(sid), resolveFlags, desc);
1347
/* Proposed default [[GetP]](Receiver, P) method. */
1349
GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index,
1350
unsigned resolveFlags, Value *vp);
1353
DefineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, const PropDesc &desc,
1354
bool shouldThrow, unsigned resolveFlags, bool *succeeded);
1356
/* Proposed default [[SetP]](Receiver, P, V) method. */
1358
SetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index,
1359
const Value &v, unsigned resolveFlags, bool *succeeded);
1362
HasElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
1365
} /* namespace js */
1368
template <> struct RootMethods<js::PropertyId>
1370
static js::PropertyId initial() { return js::PropertyId(); }
1371
static ThingRootKind kind() { return THING_ROOT_PROPERTY_ID; }
1372
static bool poisoned(js::PropertyId propid) { return IsPoisonedId(propid.asId()); }
1376
#endif /* ObjectImpl_h__ */