~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/vm/ObjectImpl.h

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "vm/NumericConversions.h"
 
20
#include "vm/String.h"
 
21
 
 
22
namespace js {
 
23
 
 
24
class Debugger;
 
25
class ObjectImpl;
 
26
 
 
27
class AutoPropDescArrayRooter;
 
28
 
 
29
static inline PropertyOp
 
30
CastAsPropertyOp(JSObject *object)
 
31
{
 
32
    return JS_DATA_TO_FUNC_PTR(PropertyOp, object);
 
33
}
 
34
 
 
35
static inline StrictPropertyOp
 
36
CastAsStrictPropertyOp(JSObject *object)
 
37
{
 
38
    return JS_DATA_TO_FUNC_PTR(StrictPropertyOp, object);
 
39
}
 
40
 
 
41
/*
 
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.
 
51
 */
 
52
class PropertyId
 
53
{
 
54
    jsid id;
 
55
 
 
56
  public:
 
57
    bool isName() const {
 
58
        MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SPECIAL(id));
 
59
        return JSID_IS_STRING(id);
 
60
    }
 
61
    bool isSpecial() const {
 
62
        MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SPECIAL(id));
 
63
        return !isName();
 
64
    }
 
65
 
 
66
    PropertyId() {
 
67
        *this = PropertyId(SpecialId());
 
68
    }
 
69
    explicit PropertyId(PropertyName *name)
 
70
      : id(NON_INTEGER_ATOM_TO_JSID(name))
 
71
    { }
 
72
    explicit PropertyId(const SpecialId &sid)
 
73
      : id(SPECIALID_TO_JSID(sid))
 
74
    { }
 
75
 
 
76
    PropertyName * asName() const {
 
77
        return JSID_TO_STRING(id)->asAtom().asPropertyName();
 
78
    }
 
79
    SpecialId asSpecial() const {
 
80
        return JSID_TO_SPECIALID(id);
 
81
    }
 
82
    const jsid &asId() const {
 
83
        return id;
 
84
    }
 
85
    jsid &asId() {
 
86
        return id;
 
87
    }
 
88
 
 
89
    bool operator==(const PropertyId &rhs) const { return id == rhs.id; }
 
90
    bool operator!=(const PropertyId &rhs) const { return id != rhs.id; }
 
91
};
 
92
 
 
93
/*
 
94
 * A representation of ECMA-262 ed. 5's internal Property Descriptor data
 
95
 * structure.
 
96
 */
 
97
struct PropDesc {
 
98
  private:
 
99
    /*
 
100
     * Original object from which this descriptor derives, passed through for
 
101
     * the benefit of proxies.  FIXME: Remove this when direct proxies happen.
 
102
     */
 
103
    Value pd_;
 
104
 
 
105
    Value value_, get_, set_;
 
106
 
 
107
    /* Property descriptor boolean fields. */
 
108
    uint8_t attrs;
 
109
 
 
110
    /* Bits indicating which values are set. */
 
111
    bool hasGet_ : 1;
 
112
    bool hasSet_ : 1;
 
113
    bool hasValue_ : 1;
 
114
    bool hasWritable_ : 1;
 
115
    bool hasEnumerable_ : 1;
 
116
    bool hasConfigurable_ : 1;
 
117
 
 
118
    /* Or maybe this represents a property's absence, and it's undefined. */
 
119
    bool isUndefined_ : 1;
 
120
 
 
121
    PropDesc(const Value &v)
 
122
      : pd_(UndefinedValue()),
 
123
        value_(v),
 
124
        get_(UndefinedValue()), set_(UndefinedValue()),
 
125
        attrs(0),
 
126
        hasGet_(false), hasSet_(false),
 
127
        hasValue_(true), hasWritable_(false), hasEnumerable_(false), hasConfigurable_(false),
 
128
        isUndefined_(false)
 
129
    {
 
130
    }
 
131
 
 
132
  public:
 
133
    friend class AutoPropDescArrayRooter;
 
134
    friend void JS::AutoGCRooter::trace(JSTracer *trc);
 
135
 
 
136
    enum Enumerability { Enumerable = true, NonEnumerable = false };
 
137
    enum Configurability { Configurable = true, NonConfigurable = false };
 
138
    enum Writability { Writable = true, NonWritable = false };
 
139
 
 
140
    PropDesc();
 
141
 
 
142
    static PropDesc undefined() { return PropDesc(); }
 
143
    static PropDesc valueOnly(const Value &v) { return PropDesc(v); }
 
144
 
 
145
    PropDesc(const Value &v, Writability writable,
 
146
             Enumerability enumerable, Configurability configurable)
 
147
      : pd_(UndefinedValue()),
 
148
        value_(v),
 
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),
 
155
        isUndefined_(false)
 
156
    {}
 
157
 
 
158
    inline PropDesc(const Value &getter, const Value &setter,
 
159
                    Enumerability enumerable, Configurability configurable);
 
160
 
 
161
    /*
 
162
     * 8.10.5 ToPropertyDescriptor(Obj)
 
163
     *
 
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.
 
166
     *
 
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.)
 
170
     */
 
171
    bool initialize(JSContext* cx, const Value &v, bool checkAccessors = true);
 
172
 
 
173
    /*
 
174
     * 8.10.4 FromPropertyDescriptor(Desc)
 
175
     *
 
176
     * initFromPropertyDescriptor sets pd to undefined and populates all the
 
177
     * other fields of this PropDesc from desc.
 
178
     *
 
179
     * makeObject populates pd based on the other fields of *this, creating a
 
180
     * new property descriptor JSObject and defining properties on it.
 
181
     */
 
182
    void initFromPropertyDescriptor(const PropertyDescriptor &desc);
 
183
    bool makeObject(JSContext *cx);
 
184
 
 
185
    void setUndefined() { isUndefined_ = true; }
 
186
 
 
187
    bool isUndefined() const { return isUndefined_; }
 
188
 
 
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_; }
 
195
 
 
196
    Value pd() const { MOZ_ASSERT(!isUndefined()); return pd_; }
 
197
    void clearPd() { pd_ = UndefinedValue(); }
 
198
 
 
199
    uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; }
 
200
 
 
201
    /* 8.10.1 IsAccessorDescriptor(desc) */
 
202
    bool isAccessorDescriptor() const {
 
203
        return !isUndefined() && (hasGet() || hasSet());
 
204
    }
 
205
 
 
206
    /* 8.10.2 IsDataDescriptor(desc) */
 
207
    bool isDataDescriptor() const {
 
208
        return !isUndefined() && (hasValue() || hasWritable());
 
209
    }
 
210
 
 
211
    /* 8.10.3 IsGenericDescriptor(desc) */
 
212
    bool isGenericDescriptor() const {
 
213
        return !isUndefined() && !isAccessorDescriptor() && !isDataDescriptor();
 
214
    }
 
215
 
 
216
    bool configurable() const {
 
217
        MOZ_ASSERT(!isUndefined());
 
218
        MOZ_ASSERT(hasConfigurable());
 
219
        return (attrs & JSPROP_PERMANENT) == 0;
 
220
    }
 
221
 
 
222
    bool enumerable() const {
 
223
        MOZ_ASSERT(!isUndefined());
 
224
        MOZ_ASSERT(hasEnumerable());
 
225
        return (attrs & JSPROP_ENUMERATE) != 0;
 
226
    }
 
227
 
 
228
    bool writable() const {
 
229
        MOZ_ASSERT(!isUndefined());
 
230
        MOZ_ASSERT(hasWritable());
 
231
        return (attrs & JSPROP_READONLY) == 0;
 
232
    }
 
233
 
 
234
    HandleValue value() const {
 
235
        MOZ_ASSERT(hasValue());
 
236
        return HandleValue::fromMarkedLocation(&value_);
 
237
    }
 
238
 
 
239
    JSObject * getterObject() const {
 
240
        MOZ_ASSERT(!isUndefined());
 
241
        MOZ_ASSERT(hasGet());
 
242
        return get_.isUndefined() ? NULL : &get_.toObject();
 
243
    }
 
244
    JSObject * setterObject() const {
 
245
        MOZ_ASSERT(!isUndefined());
 
246
        MOZ_ASSERT(hasSet());
 
247
        return set_.isUndefined() ? NULL : &set_.toObject();
 
248
    }
 
249
 
 
250
    HandleValue getterValue() const {
 
251
        MOZ_ASSERT(!isUndefined());
 
252
        MOZ_ASSERT(hasGet());
 
253
        return HandleValue::fromMarkedLocation(&get_);
 
254
    }
 
255
    HandleValue setterValue() const {
 
256
        MOZ_ASSERT(!isUndefined());
 
257
        MOZ_ASSERT(hasSet());
 
258
        return HandleValue::fromMarkedLocation(&set_);
 
259
    }
 
260
 
 
261
    /*
 
262
     * Unfortunately the values produced by these methods are used such that
 
263
     * we can't assert anything here.  :-(
 
264
     */
 
265
    PropertyOp getter() const {
 
266
        return CastAsPropertyOp(get_.isUndefined() ? NULL : &get_.toObject());
 
267
    }
 
268
    StrictPropertyOp setter() const {
 
269
        return CastAsStrictPropertyOp(set_.isUndefined() ? NULL : &set_.toObject());
 
270
    }
 
271
 
 
272
    /*
 
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.
 
276
     */
 
277
    bool checkGetter(JSContext *cx);
 
278
    bool checkSetter(JSContext *cx);
 
279
 
 
280
    bool unwrapDebuggerObjectsInto(JSContext *cx, Debugger *dbg, JSObject *obj,
 
281
                                   PropDesc *unwrapped) const;
 
282
 
 
283
    bool wrapInto(JSContext *cx, JSObject *obj, const jsid &id, jsid *wrappedId,
 
284
                  PropDesc *wrappedDesc) const;
 
285
 
 
286
    class AutoRooter : private AutoGCRooter
 
287
    {
 
288
      public:
 
289
        explicit AutoRooter(JSContext *cx, PropDesc *pd_
 
290
                            JS_GUARD_OBJECT_NOTIFIER_PARAM)
 
291
          : AutoGCRooter(cx, PROPDESC), pd(pd_), skip(cx, pd_)
 
292
        {
 
293
            JS_GUARD_OBJECT_NOTIFIER_INIT;
 
294
        }
 
295
 
 
296
        friend void AutoGCRooter::trace(JSTracer *trc);
 
297
 
 
298
      private:
 
299
        PropDesc *pd;
 
300
        SkipRoot skip;
 
301
        JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
302
     };
 
303
};
 
304
 
 
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;
 
318
 
 
319
enum ElementsKind {
 
320
    DenseElements,
 
321
    SparseElements,
 
322
 
 
323
    ArrayBufferElements,
 
324
 
 
325
    /* These typed element types must remain contiguous. */
 
326
    Uint8Elements,
 
327
    Int8Elements,
 
328
    Uint16Elements,
 
329
    Int16Elements,
 
330
    Uint32Elements,
 
331
    Int32Elements,
 
332
    Uint8ClampedElements,
 
333
    Float32Elements,
 
334
    Float64Elements
 
335
};
 
336
 
 
337
class ElementsHeader
 
338
{
 
339
  protected:
 
340
    uint32_t type;
 
341
    uint32_t length; /* Array length, ArrayBuffer length, typed array length */
 
342
 
 
343
    union {
 
344
        class {
 
345
            friend class DenseElementsHeader;
 
346
            uint32_t initializedLength;
 
347
            uint32_t capacity;
 
348
        } dense;
 
349
        class {
 
350
            friend class SparseElementsHeader;
 
351
            Shape * shape;
 
352
        } sparse;
 
353
    };
 
354
 
 
355
    void staticAsserts() {
 
356
        MOZ_STATIC_ASSERT(sizeof(ElementsHeader) == ValuesPerHeader * sizeof(Value),
 
357
                          "Elements size and values-per-Elements mismatch");
 
358
    }
 
359
 
 
360
  public:
 
361
    ElementsKind kind() const {
 
362
        MOZ_ASSERT(type <= ArrayBufferElements);
 
363
        return ElementsKind(type);
 
364
    }
 
365
 
 
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; }
 
378
 
 
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();
 
391
 
 
392
    static ElementsHeader * fromElements(HeapSlot *elems) {
 
393
        return reinterpret_cast<ElementsHeader *>(uintptr_t(elems) - sizeof(ElementsHeader));
 
394
    }
 
395
 
 
396
    static const size_t ValuesPerHeader = 2;
 
397
};
 
398
 
 
399
class DenseElementsHeader : public ElementsHeader
 
400
{
 
401
  public:
 
402
    uint32_t capacity() const {
 
403
        MOZ_ASSERT(ElementsHeader::isDenseElements());
 
404
        return dense.capacity;
 
405
    }
 
406
 
 
407
    uint32_t initializedLength() const {
 
408
        MOZ_ASSERT(ElementsHeader::isDenseElements());
 
409
        return dense.initializedLength;
 
410
    }
 
411
 
 
412
    uint32_t length() const {
 
413
        MOZ_ASSERT(ElementsHeader::isDenseElements());
 
414
        return ElementsHeader::length;
 
415
    }
 
416
 
 
417
    bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
418
                       unsigned resolveFlags, PropDesc *desc);
 
419
 
 
420
    bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
421
                       const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
 
422
                       bool *succeeded);
 
423
 
 
424
    bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
 
425
                    uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
 
426
 
 
427
  private:
 
428
    inline bool isDenseElements() const MOZ_DELETE;
 
429
    inline DenseElementsHeader & asDenseElements() MOZ_DELETE;
 
430
 
 
431
    DenseElementsHeader(const DenseElementsHeader &other) MOZ_DELETE;
 
432
    void operator=(const DenseElementsHeader &other) MOZ_DELETE;
 
433
};
 
434
 
 
435
class SparseElementsHeader : public ElementsHeader
 
436
{
 
437
  public:
 
438
    Shape * shape() {
 
439
        MOZ_ASSERT(ElementsHeader::isSparseElements());
 
440
        return sparse.shape;
 
441
    }
 
442
 
 
443
    uint32_t length() const {
 
444
        MOZ_ASSERT(ElementsHeader::isSparseElements());
 
445
        return ElementsHeader::length;
 
446
    }
 
447
 
 
448
    bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
449
                       unsigned resolveFlags, PropDesc *desc);
 
450
 
 
451
    bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
452
                       const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
 
453
                       bool *succeeded);
 
454
 
 
455
    bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
 
456
                    uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
 
457
 
 
458
  private:
 
459
    inline bool isSparseElements() const MOZ_DELETE;
 
460
    inline SparseElementsHeader & asSparseElements() MOZ_DELETE;
 
461
 
 
462
    SparseElementsHeader(const SparseElementsHeader &other) MOZ_DELETE;
 
463
    void operator=(const SparseElementsHeader &other) MOZ_DELETE;
 
464
};
 
465
 
 
466
extern uint32_t JS_FASTCALL
 
467
ClampDoubleToUint8(const double x);
 
468
 
 
469
struct uint8_clamped {
 
470
    uint8_t val;
 
471
 
 
472
    uint8_clamped() { }
 
473
    uint8_clamped(const uint8_clamped& other) : val(other.val) { }
 
474
 
 
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; }
 
483
 
 
484
    uint8_clamped& operator=(const uint8_clamped& x) {
 
485
        val = x.val;
 
486
        return *this;
 
487
    }
 
488
 
 
489
    uint8_clamped& operator=(uint8_t x) {
 
490
        val = x;
 
491
        return *this;
 
492
    }
 
493
 
 
494
    uint8_clamped& operator=(uint16_t x) {
 
495
        val = (x > 255) ? 255 : uint8_t(x);
 
496
        return *this;
 
497
    }
 
498
 
 
499
    uint8_clamped& operator=(uint32_t x) {
 
500
        val = (x > 255) ? 255 : uint8_t(x);
 
501
        return *this;
 
502
    }
 
503
 
 
504
    uint8_clamped& operator=(int8_t x) {
 
505
        val = (x >= 0) ? uint8_t(x) : 0;
 
506
        return *this;
 
507
    }
 
508
 
 
509
    uint8_clamped& operator=(int16_t x) {
 
510
        val = (x >= 0)
 
511
              ? ((x < 255)
 
512
                 ? uint8_t(x)
 
513
                 : 255)
 
514
              : 0;
 
515
        return *this;
 
516
    }
 
517
 
 
518
    uint8_clamped& operator=(int32_t x) {
 
519
        val = (x >= 0)
 
520
              ? ((x < 255)
 
521
                 ? uint8_t(x)
 
522
                 : 255)
 
523
              : 0;
 
524
        return *this;
 
525
    }
 
526
 
 
527
    uint8_clamped& operator=(const double x) {
 
528
        val = uint8_t(ClampDoubleToUint8(x));
 
529
        return *this;
 
530
    }
 
531
 
 
532
    operator uint8_t() const {
 
533
        return val;
 
534
    }
 
535
 
 
536
    void staticAsserts() {
 
537
        MOZ_STATIC_ASSERT(sizeof(uint8_clamped) == 1,
 
538
                          "uint8_clamped must be layout-compatible with uint8_t");
 
539
    }
 
540
};
 
541
 
 
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; }
 
546
 
 
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; }
 
551
 
 
552
template <typename T>
 
553
class TypedElementsHeader : public ElementsHeader
 
554
{
 
555
    T getElement(uint32_t index) {
 
556
        MOZ_ASSERT(index < length());
 
557
        return reinterpret_cast<T *>(this + 1)[index];
 
558
    }
 
559
 
 
560
    inline void assign(uint32_t index, double d);
 
561
 
 
562
    void setElement(uint32_t index, T value) {
 
563
        MOZ_ASSERT(index < length());
 
564
        reinterpret_cast<T *>(this + 1)[index] = value;
 
565
    }
 
566
 
 
567
  public:
 
568
    uint32_t length() const {
 
569
        MOZ_ASSERT(Uint8Elements <= kind());
 
570
        MOZ_ASSERT(kind() <= Float64Elements);
 
571
        return ElementsHeader::length;
 
572
    }
 
573
 
 
574
    bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
575
                       unsigned resolveFlags, PropDesc *desc);
 
576
 
 
577
    bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
578
                       const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
 
579
                       bool *succeeded);
 
580
 
 
581
    bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
 
582
                    uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
 
583
 
 
584
  private:
 
585
    TypedElementsHeader(const TypedElementsHeader &other) MOZ_DELETE;
 
586
    void operator=(const TypedElementsHeader &other) MOZ_DELETE;
 
587
};
 
588
 
 
589
template<typename T> inline void
 
590
TypedElementsHeader<T>::assign(uint32_t index, double d)
 
591
{
 
592
    MOZ_NOT_REACHED("didn't specialize for this element type");
 
593
}
 
594
 
 
595
template<> inline void
 
596
TypedElementsHeader<uint8_clamped>::assign(uint32_t index, double d)
 
597
{
 
598
    double i = ToInteger(d);
 
599
    uint8_t u = (i <= 0)
 
600
                ? 0
 
601
                : (i >= 255)
 
602
                ? 255
 
603
                : uint8_t(i);
 
604
    setElement(index, uint8_clamped(u));
 
605
}
 
606
 
 
607
template<> inline void
 
608
TypedElementsHeader<uint8_t>::assign(uint32_t index, double d)
 
609
{
 
610
    setElement(index, uint8_t(ToUint32(d)));
 
611
}
 
612
 
 
613
template<> inline void
 
614
TypedElementsHeader<int8_t>::assign(uint32_t index, double d)
 
615
{
 
616
    /* FIXME: Casting out-of-range signed integers has undefined behavior! */
 
617
    setElement(index, int8_t(ToInt32(d)));
 
618
}
 
619
 
 
620
template<> inline void
 
621
TypedElementsHeader<uint16_t>::assign(uint32_t index, double d)
 
622
{
 
623
    setElement(index, uint16_t(ToUint32(d)));
 
624
}
 
625
 
 
626
template<> inline void
 
627
TypedElementsHeader<int16_t>::assign(uint32_t index, double d)
 
628
{
 
629
    /* FIXME: Casting out-of-range signed integers has undefined behavior! */
 
630
    setElement(index, int16_t(ToInt32(d)));
 
631
}
 
632
 
 
633
template<> inline void
 
634
TypedElementsHeader<uint32_t>::assign(uint32_t index, double d)
 
635
{
 
636
    setElement(index, ToUint32(d));
 
637
}
 
638
 
 
639
template<> inline void
 
640
TypedElementsHeader<int32_t>::assign(uint32_t index, double d)
 
641
{
 
642
    /* FIXME: Casting out-of-range signed integers has undefined behavior! */
 
643
    setElement(index, int32_t(ToInt32(d)));
 
644
}
 
645
 
 
646
template<> inline void
 
647
TypedElementsHeader<float>::assign(uint32_t index, double d)
 
648
{
 
649
    setElement(index, float(d));
 
650
}
 
651
 
 
652
template<> inline void
 
653
TypedElementsHeader<double>::assign(uint32_t index, double d)
 
654
{
 
655
    setElement(index, d);
 
656
}
 
657
 
 
658
class Uint8ElementsHeader : public TypedElementsHeader<uint8_t>
 
659
{
 
660
  private:
 
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;
 
665
};
 
666
class Int8ElementsHeader : public TypedElementsHeader<int8_t>
 
667
{
 
668
  private:
 
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;
 
673
};
 
674
class Uint16ElementsHeader : public TypedElementsHeader<uint16_t>
 
675
{
 
676
  private:
 
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;
 
681
};
 
682
class Int16ElementsHeader : public TypedElementsHeader<int16_t>
 
683
{
 
684
  private:
 
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;
 
689
};
 
690
class Uint32ElementsHeader : public TypedElementsHeader<uint32_t>
 
691
{
 
692
  private:
 
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;
 
697
};
 
698
class Int32ElementsHeader : public TypedElementsHeader<int32_t>
 
699
{
 
700
  private:
 
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;
 
705
};
 
706
class Float32ElementsHeader : public TypedElementsHeader<float>
 
707
{
 
708
  private:
 
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;
 
713
};
 
714
class Float64ElementsHeader : public TypedElementsHeader<double>
 
715
{
 
716
  private:
 
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;
 
721
};
 
722
 
 
723
class Uint8ClampedElementsHeader : public TypedElementsHeader<uint8_clamped>
 
724
{
 
725
  private:
 
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;
 
730
};
 
731
 
 
732
class ArrayBufferElementsHeader : public ElementsHeader
 
733
{
 
734
  public:
 
735
    bool getOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
736
                       unsigned resolveFlags, PropDesc *desc);
 
737
 
 
738
    bool defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index,
 
739
                       const PropDesc &desc, bool shouldThrow, unsigned resolveFlags,
 
740
                       bool *succeeded);
 
741
 
 
742
    bool setElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver,
 
743
                    uint32_t index, const Value &v, unsigned resolveFlags, bool *succeeded);
 
744
 
 
745
  private:
 
746
    inline bool isArrayBufferElements() const MOZ_DELETE;
 
747
    inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE;
 
748
 
 
749
    ArrayBufferElementsHeader(const ArrayBufferElementsHeader &other) MOZ_DELETE;
 
750
    void operator=(const ArrayBufferElementsHeader &other) MOZ_DELETE;
 
751
};
 
752
 
 
753
inline DenseElementsHeader &
 
754
ElementsHeader::asDenseElements()
 
755
{
 
756
    MOZ_ASSERT(isDenseElements());
 
757
    return *static_cast<DenseElementsHeader *>(this);
 
758
}
 
759
 
 
760
inline SparseElementsHeader &
 
761
ElementsHeader::asSparseElements()
 
762
{
 
763
    MOZ_ASSERT(isSparseElements());
 
764
    return *static_cast<SparseElementsHeader *>(this);
 
765
}
 
766
 
 
767
inline Uint8ElementsHeader &
 
768
ElementsHeader::asUint8Elements()
 
769
{
 
770
    MOZ_ASSERT(isUint8Elements());
 
771
    return *static_cast<Uint8ElementsHeader *>(this);
 
772
}
 
773
 
 
774
inline Int8ElementsHeader &
 
775
ElementsHeader::asInt8Elements()
 
776
{
 
777
    MOZ_ASSERT(isInt8Elements());
 
778
    return *static_cast<Int8ElementsHeader *>(this);
 
779
}
 
780
 
 
781
inline Uint16ElementsHeader &
 
782
ElementsHeader::asUint16Elements()
 
783
{
 
784
    MOZ_ASSERT(isUint16Elements());
 
785
    return *static_cast<Uint16ElementsHeader *>(this);
 
786
}
 
787
 
 
788
inline Int16ElementsHeader &
 
789
ElementsHeader::asInt16Elements()
 
790
{
 
791
    MOZ_ASSERT(isInt16Elements());
 
792
    return *static_cast<Int16ElementsHeader *>(this);
 
793
}
 
794
 
 
795
inline Uint32ElementsHeader &
 
796
ElementsHeader::asUint32Elements()
 
797
{
 
798
    MOZ_ASSERT(isUint32Elements());
 
799
    return *static_cast<Uint32ElementsHeader *>(this);
 
800
}
 
801
 
 
802
inline Int32ElementsHeader &
 
803
ElementsHeader::asInt32Elements()
 
804
{
 
805
    MOZ_ASSERT(isInt32Elements());
 
806
    return *static_cast<Int32ElementsHeader *>(this);
 
807
}
 
808
 
 
809
inline Uint8ClampedElementsHeader &
 
810
ElementsHeader::asUint8ClampedElements()
 
811
{
 
812
    MOZ_ASSERT(isUint8ClampedElements());
 
813
    return *static_cast<Uint8ClampedElementsHeader *>(this);
 
814
}
 
815
 
 
816
inline Float32ElementsHeader &
 
817
ElementsHeader::asFloat32Elements()
 
818
{
 
819
    MOZ_ASSERT(isFloat32Elements());
 
820
    return *static_cast<Float32ElementsHeader *>(this);
 
821
}
 
822
 
 
823
inline Float64ElementsHeader &
 
824
ElementsHeader::asFloat64Elements()
 
825
{
 
826
    MOZ_ASSERT(isFloat64Elements());
 
827
    return *static_cast<Float64ElementsHeader *>(this);
 
828
}
 
829
 
 
830
inline ArrayBufferElementsHeader &
 
831
ElementsHeader::asArrayBufferElements()
 
832
{
 
833
    MOZ_ASSERT(isArrayBufferElements());
 
834
    return *static_cast<ArrayBufferElementsHeader *>(this);
 
835
}
 
836
 
 
837
/*
 
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.
 
842
 */
 
843
class ArrayBufferObject;
 
844
class ObjectElements
 
845
{
 
846
    friend struct ::JSObject;
 
847
    friend class ObjectImpl;
 
848
    friend class ArrayBufferObject;
 
849
 
 
850
    /* Number of allocated slots. */
 
851
    uint32_t capacity;
 
852
 
 
853
    /*
 
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.
 
858
     */
 
859
    uint32_t initializedLength;
 
860
 
 
861
    /* 'length' property of array objects, unused for other objects. */
 
862
    uint32_t length;
 
863
 
 
864
    /* :XXX: bug 586842 store state about sparse slots. */
 
865
    uint32_t unused;
 
866
 
 
867
    void staticAsserts() {
 
868
        MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
 
869
                          "Elements size and values-per-Elements mismatch");
 
870
    }
 
871
 
 
872
  public:
 
873
 
 
874
    ObjectElements(uint32_t capacity, uint32_t length)
 
875
      : capacity(capacity), initializedLength(0), length(length)
 
876
    {}
 
877
 
 
878
    HeapSlot *elements() { return (HeapSlot *)(uintptr_t(this) + sizeof(ObjectElements)); }
 
879
    static ObjectElements * fromElements(HeapSlot *elems) {
 
880
        return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements));
 
881
    }
 
882
 
 
883
    static int offsetOfCapacity() {
 
884
        return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements);
 
885
    }
 
886
    static int offsetOfInitializedLength() {
 
887
        return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements);
 
888
    }
 
889
    static int offsetOfLength() {
 
890
        return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements);
 
891
    }
 
892
 
 
893
    static const size_t VALUES_PER_HEADER = 2;
 
894
};
 
895
 
 
896
/* Shared singleton for objects with no elements. */
 
897
extern HeapSlot *emptyObjectElements;
 
898
 
 
899
struct Class;
 
900
struct GCMarker;
 
901
struct ObjectOps;
 
902
struct Shape;
 
903
 
 
904
class NewObjectCache;
 
905
 
 
906
inline Value
 
907
ObjectValue(ObjectImpl &obj);
 
908
 
 
909
/*
 
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.)
 
913
 *
 
914
 * The |shape_| member stores the shape of the object, which includes the
 
915
 * object's class and the layout of all its properties.
 
916
 *
 
917
 * The type member stores the type of the object, which contains its prototype
 
918
 * object and the possible types of its properties.
 
919
 *
 
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.
 
924
 *
 
925
 * Two native objects with the same shape are guaranteed to have the same
 
926
 * number of fixed slots.
 
927
 *
 
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.
 
933
 *
 
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.
 
938
 *
 
939
 * Only certain combinations of properties and elements storage are currently
 
940
 * possible. This will be changing soon :XXX: bug 586842.
 
941
 *
 
942
 * - For objects other than arrays and typed arrays, the elements are empty.
 
943
 *
 
944
 * - For 'slow' arrays, both elements and properties are used, but the
 
945
 *   elements have zero capacity --- only the length member is used.
 
946
 *
 
947
 * - For dense arrays, elements are used and properties are not used.
 
948
 *
 
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.
 
952
 *
 
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.
 
956
 */
 
957
class ObjectImpl : public gc::Cell
 
958
{
 
959
  protected:
 
960
    /*
 
961
     * Shape of the object, encodes the layout of the object's properties and
 
962
     * all other information about its structure. See jsscope.h.
 
963
     */
 
964
    HeapPtrShape shape_;
 
965
 
 
966
    /*
 
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.
 
970
     */
 
971
    HeapPtrTypeObject type_;
 
972
 
 
973
    HeapSlot *slots;     /* Slots for object properties. */
 
974
    HeapSlot *elements;  /* Slots for object elements. */
 
975
 
 
976
  private:
 
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");
 
982
 
 
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");
 
991
    }
 
992
 
 
993
    JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
 
994
 
 
995
    friend inline Value ObjectValue(ObjectImpl &obj);
 
996
 
 
997
    /* These functions are public, and they should remain public. */
 
998
 
 
999
  public:
 
1000
    JSObject * getProto() const {
 
1001
        return type_->proto;
 
1002
    }
 
1003
 
 
1004
    inline bool isExtensible() const;
 
1005
 
 
1006
    /*
 
1007
     * XXX Once the property/element split of bug 586842 is complete, these
 
1008
     *     methods should move back to JSObject.
 
1009
     */
 
1010
    inline bool isDenseArray() const;
 
1011
    inline bool isSlowArray() const;
 
1012
    inline bool isArray() const;
 
1013
 
 
1014
    inline HeapSlotArray getDenseArrayElements();
 
1015
    inline const Value & getDenseArrayElement(uint32_t idx);
 
1016
    inline uint32_t getDenseArrayInitializedLength();
 
1017
 
 
1018
    bool makeElementsSparse(JSContext *cx) {
 
1019
        NEW_OBJECT_REPRESENTATION_ONLY();
 
1020
 
 
1021
        MOZ_NOT_REACHED("NYI");
 
1022
        return false;
 
1023
    }
 
1024
 
 
1025
  protected:
 
1026
#ifdef DEBUG
 
1027
    void checkShapeConsistency();
 
1028
#else
 
1029
    void checkShapeConsistency() { }
 
1030
#endif
 
1031
 
 
1032
  private:
 
1033
    /*
 
1034
     * Get internal pointers to the range of values starting at start and
 
1035
     * running for length.
 
1036
     */
 
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);
 
1043
 
 
1044
  protected:
 
1045
    friend struct GCMarker;
 
1046
    friend struct Shape;
 
1047
    friend class NewObjectCache;
 
1048
 
 
1049
    inline void invalidateSlotRange(uint32_t start, uint32_t count);
 
1050
    inline void initializeSlotRange(uint32_t start, uint32_t count);
 
1051
 
 
1052
    /*
 
1053
     * Initialize a flat array of slots to this object at a start slot.  The
 
1054
     * caller must ensure that are enough slots.
 
1055
     */
 
1056
    void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
 
1057
 
 
1058
    /*
 
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.
 
1061
     */
 
1062
    void copySlotRange(uint32_t start, const Value *vector, uint32_t length);
 
1063
 
 
1064
#ifdef DEBUG
 
1065
    enum SentinelAllowed {
 
1066
        SENTINEL_NOT_ALLOWED,
 
1067
        SENTINEL_ALLOWED
 
1068
    };
 
1069
 
 
1070
    /*
 
1071
     * Check that slot is in range for the object's allocated slots.
 
1072
     * If sentinelAllowed then slot may equal the slot capacity.
 
1073
     */
 
1074
    bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
 
1075
#endif
 
1076
 
 
1077
    /* Minimum size for dynamically allocated slots. */
 
1078
    static const uint32_t SLOT_CAPACITY_MIN = 8;
 
1079
 
 
1080
    HeapSlot *fixedSlots() const {
 
1081
        return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
 
1082
    }
 
1083
 
 
1084
    friend class ElementsHeader;
 
1085
    friend class DenseElementsHeader;
 
1086
    friend class SparseElementsHeader;
 
1087
 
 
1088
    enum DenseElementsResult {
 
1089
        Failure,
 
1090
        ConvertToSparse,
 
1091
        Succeeded
 
1092
    };
 
1093
 
 
1094
    DenseElementsResult ensureDenseElementsInitialized(JSContext *cx, uint32_t index,
 
1095
                                                       uint32_t extra)
 
1096
    {
 
1097
        NEW_OBJECT_REPRESENTATION_ONLY();
 
1098
 
 
1099
        MOZ_NOT_REACHED("NYI");
 
1100
        return Failure;
 
1101
    }
 
1102
 
 
1103
    /*
 
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.
 
1106
     */
 
1107
 
 
1108
  public:
 
1109
    Shape * lastProperty() const {
 
1110
        MOZ_ASSERT(shape_);
 
1111
        return shape_;
 
1112
    }
 
1113
 
 
1114
    inline bool isNative() const;
 
1115
 
 
1116
    types::TypeObject *type() const {
 
1117
        MOZ_ASSERT(!hasLazyType());
 
1118
        return type_;
 
1119
    }
 
1120
 
 
1121
    uint32_t numFixedSlots() const {
 
1122
        return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
 
1123
    }
 
1124
 
 
1125
    /*
 
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.
 
1128
     */
 
1129
    bool hasSingletonType() const { return !!type_->singleton; }
 
1130
 
 
1131
    /*
 
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().
 
1134
     */
 
1135
    bool hasLazyType() const { return type_->lazy(); }
 
1136
 
 
1137
    inline uint32_t slotSpan() const;
 
1138
 
 
1139
    /* Compute dynamicSlotsCount() for this object. */
 
1140
    inline uint32_t numDynamicSlots() const;
 
1141
 
 
1142
    Shape * nativeLookup(JSContext *cx, jsid id);
 
1143
    inline Shape * nativeLookup(JSContext *cx, PropertyId pid);
 
1144
    inline Shape * nativeLookup(JSContext *cx, PropertyName *name);
 
1145
 
 
1146
    Shape * nativeLookupNoAllocation(jsid id);
 
1147
    inline Shape * nativeLookupNoAllocation(PropertyId pid);
 
1148
    inline Shape * nativeLookupNoAllocation(PropertyName *name);
 
1149
 
 
1150
    inline Class *getClass() const;
 
1151
    inline JSClass *getJSClass() const;
 
1152
    inline bool hasClass(const Class *c) const;
 
1153
    inline const ObjectOps *getOps() const;
 
1154
 
 
1155
    /*
 
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).
 
1163
     */
 
1164
    inline bool isDelegate() const;
 
1165
 
 
1166
    /*
 
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.
 
1170
     */
 
1171
    inline bool inDictionaryMode() const;
 
1172
 
 
1173
    const Value &getSlot(uint32_t slot) const {
 
1174
        MOZ_ASSERT(slotInRange(slot));
 
1175
        uint32_t fixed = numFixedSlots();
 
1176
        if (slot < fixed)
 
1177
            return fixedSlots()[slot];
 
1178
        return slots[slot - fixed];
 
1179
    }
 
1180
 
 
1181
    HeapSlot *getSlotAddressUnchecked(uint32_t slot) {
 
1182
        uint32_t fixed = numFixedSlots();
 
1183
        if (slot < fixed)
 
1184
            return fixedSlots() + slot;
 
1185
        return slots + (slot - fixed);
 
1186
    }
 
1187
 
 
1188
    HeapSlot *getSlotAddress(uint32_t slot) {
 
1189
        /*
 
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).
 
1193
         */
 
1194
        MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
 
1195
        return getSlotAddressUnchecked(slot);
 
1196
    }
 
1197
 
 
1198
    HeapSlot &getSlotRef(uint32_t slot) {
 
1199
        MOZ_ASSERT(slotInRange(slot));
 
1200
        return *getSlotAddress(slot);
 
1201
    }
 
1202
 
 
1203
    inline HeapSlot &nativeGetSlotRef(uint32_t slot);
 
1204
    inline const Value &nativeGetSlot(uint32_t slot) const;
 
1205
 
 
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);
 
1210
 
 
1211
    /* For slots which are known to always be fixed, due to the way they are allocated. */
 
1212
 
 
1213
    HeapSlot &getFixedSlotRef(uint32_t slot) {
 
1214
        MOZ_ASSERT(slot < numFixedSlots());
 
1215
        return fixedSlots()[slot];
 
1216
    }
 
1217
 
 
1218
    const Value &getFixedSlot(uint32_t slot) const {
 
1219
        MOZ_ASSERT(slot < numFixedSlots());
 
1220
        return fixedSlots()[slot];
 
1221
    }
 
1222
 
 
1223
    inline void setFixedSlot(uint32_t slot, const Value &value);
 
1224
    inline void initFixedSlot(uint32_t slot, const Value &value);
 
1225
 
 
1226
    /*
 
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.
 
1231
     */
 
1232
    static inline uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span);
 
1233
 
 
1234
    /* Memory usage functions. */
 
1235
    inline size_t sizeOfThis() const;
 
1236
 
 
1237
    /* Elements accessors. */
 
1238
 
 
1239
    ObjectElements * getElementsHeader() const {
 
1240
        return ObjectElements::fromElements(elements);
 
1241
    }
 
1242
 
 
1243
    ElementsHeader & elementsHeader() const {
 
1244
        NEW_OBJECT_REPRESENTATION_ONLY();
 
1245
        return *ElementsHeader::fromElements(elements);
 
1246
    }
 
1247
 
 
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];
 
1253
    }
 
1254
 
 
1255
    void setFixedElements() { this->elements = fixedElements(); }
 
1256
 
 
1257
    inline bool hasDynamicElements() const {
 
1258
        /*
 
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.
 
1264
         */
 
1265
        return elements != emptyObjectElements && elements != fixedElements();
 
1266
    }
 
1267
 
 
1268
    /* GC support. */
 
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);
 
1276
 
 
1277
    /* Private data accessors. */
 
1278
 
 
1279
    inline void *&privateRef(uint32_t nfixed) const; /* XXX should be private, not protected! */
 
1280
 
 
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);
 
1287
 
 
1288
    /* Access private data for an object with a known number of fixed slots. */
 
1289
    inline void *getPrivate(uint32_t nfixed) const;
 
1290
 
 
1291
    /* JIT Accessors */
 
1292
    static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
 
1293
    HeapPtrShape *addressOfShape() { return &shape_; }
 
1294
 
 
1295
    static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
 
1296
    HeapPtrTypeObject *addressOfType() { return &type_; }
 
1297
 
 
1298
    static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
 
1299
    static size_t offsetOfFixedElements() {
 
1300
        return sizeof(ObjectImpl) + sizeof(ObjectElements);
 
1301
    }
 
1302
 
 
1303
    static size_t getFixedSlotOffset(size_t slot) {
 
1304
        return sizeof(ObjectImpl) + slot * sizeof(Value);
 
1305
    }
 
1306
    static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
 
1307
    static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
 
1308
};
 
1309
 
 
1310
inline Value
 
1311
ObjectValue(ObjectImpl &obj)
 
1312
{
 
1313
    Value v;
 
1314
    v.setObject(*obj.asObjectPtr());
 
1315
    return v;
 
1316
}
 
1317
 
 
1318
inline Handle<JSObject*>
 
1319
Downcast(Handle<ObjectImpl*> obj)
 
1320
{
 
1321
    return Handle<JSObject*>::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
 
1322
}
 
1323
 
 
1324
extern JSObject *
 
1325
ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj);
 
1326
 
 
1327
/* Generic [[GetOwnProperty]] method. */
 
1328
bool
 
1329
GetOwnElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
 
1330
              PropDesc *desc);
 
1331
extern bool
 
1332
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, PropertyId pid, unsigned resolveFlags,
 
1333
               PropDesc *desc);
 
1334
inline bool
 
1335
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<PropertyName*> name,
 
1336
               unsigned resolveFlags, PropDesc *desc)
 
1337
{
 
1338
    return GetOwnProperty(cx, obj, PropertyId(name), resolveFlags, desc);
 
1339
}
 
1340
inline bool
 
1341
GetOwnProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<SpecialId> sid, unsigned resolveFlags,
 
1342
               PropDesc *desc)
 
1343
{
 
1344
    return GetOwnProperty(cx, obj, PropertyId(sid), resolveFlags, desc);
 
1345
}
 
1346
 
 
1347
/* Proposed default [[GetP]](Receiver, P) method. */
 
1348
extern bool
 
1349
GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index,
 
1350
           unsigned resolveFlags, Value *vp);
 
1351
 
 
1352
extern bool
 
1353
DefineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, const PropDesc &desc,
 
1354
              bool shouldThrow, unsigned resolveFlags, bool *succeeded);
 
1355
 
 
1356
/* Proposed default [[SetP]](Receiver, P, V) method. */
 
1357
extern bool
 
1358
SetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index,
 
1359
           const Value &v, unsigned resolveFlags, bool *succeeded);
 
1360
 
 
1361
extern bool
 
1362
HasElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned resolveFlags,
 
1363
           bool *found);
 
1364
 
 
1365
} /* namespace js */
 
1366
 
 
1367
namespace JS {
 
1368
template <> struct RootMethods<js::PropertyId>
 
1369
{
 
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()); }
 
1373
};
 
1374
}
 
1375
 
 
1376
#endif /* ObjectImpl_h__ */