js/src/vm/ObjectImpl.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/ObjectImpl.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1014 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef vm_ObjectImpl_h
    1.11 +#define vm_ObjectImpl_h
    1.12 +
    1.13 +#include "mozilla/Assertions.h"
    1.14 +#include "mozilla/Attributes.h"
    1.15 +
    1.16 +#include <stdint.h>
    1.17 +
    1.18 +#include "jsfriendapi.h"
    1.19 +#include "jsinfer.h"
    1.20 +#include "NamespaceImports.h"
    1.21 +
    1.22 +#include "gc/Barrier.h"
    1.23 +#include "gc/Heap.h"
    1.24 +#include "gc/Marking.h"
    1.25 +#include "js/Value.h"
    1.26 +#include "vm/NumericConversions.h"
    1.27 +#include "vm/Shape.h"
    1.28 +#include "vm/String.h"
    1.29 +
    1.30 +namespace js {
    1.31 +
    1.32 +class ObjectImpl;
    1.33 +class Nursery;
    1.34 +class Shape;
    1.35 +
    1.36 +/*
    1.37 + * To really poison a set of values, using 'magic' or 'undefined' isn't good
    1.38 + * enough since often these will just be ignored by buggy code (see bug 629974)
    1.39 + * in debug builds and crash in release builds. Instead, we use a safe-for-crash
    1.40 + * pointer.
    1.41 + */
    1.42 +static MOZ_ALWAYS_INLINE void
    1.43 +Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
    1.44 +{
    1.45 +#ifdef DEBUG
    1.46 +    for (Value *v = beg; v != end; ++v)
    1.47 +        v->setObject(*reinterpret_cast<JSObject *>(0x42));
    1.48 +#endif
    1.49 +}
    1.50 +
    1.51 +static MOZ_ALWAYS_INLINE void
    1.52 +Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
    1.53 +{
    1.54 +#ifdef DEBUG
    1.55 +    Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
    1.56 +#endif
    1.57 +}
    1.58 +
    1.59 +static MOZ_ALWAYS_INLINE void
    1.60 +Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
    1.61 +{
    1.62 +#ifdef DEBUG
    1.63 +    Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
    1.64 +#endif
    1.65 +}
    1.66 +
    1.67 +static MOZ_ALWAYS_INLINE void
    1.68 +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len)
    1.69 +{
    1.70 +#ifdef DEBUG
    1.71 +    Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
    1.72 +#endif
    1.73 +}
    1.74 +
    1.75 +static MOZ_ALWAYS_INLINE void
    1.76 +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
    1.77 +{
    1.78 +#ifdef DEBUG
    1.79 +    Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
    1.80 +#endif
    1.81 +}
    1.82 +
    1.83 +class ArrayObject;
    1.84 +
    1.85 +/*
    1.86 + * ES6 20130308 draft 8.4.2.4 ArraySetLength.
    1.87 + *
    1.88 + * |id| must be "length", |attrs| are the attributes to be used for the newly-
    1.89 + * changed length property, |value| is the value for the new length, and
    1.90 + * |setterIsStrict| indicates whether invalid changes will cause a TypeError
    1.91 + * to be thrown.
    1.92 + */
    1.93 +template <ExecutionMode mode>
    1.94 +extern bool
    1.95 +ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
    1.96 +               Handle<ArrayObject*> obj, HandleId id,
    1.97 +               unsigned attrs, HandleValue value, bool setterIsStrict);
    1.98 +
    1.99 +/*
   1.100 + * Elements header used for all objects. The elements component of such objects
   1.101 + * offers an efficient representation for all or some of the indexed properties
   1.102 + * of the object, using a flat array of Values rather than a shape hierarchy
   1.103 + * stored in the object's slots. This structure is immediately followed by an
   1.104 + * array of elements, with the elements member in an object pointing to the
   1.105 + * beginning of that array (the end of this structure).
   1.106 + * See below for usage of this structure.
   1.107 + *
   1.108 + * The sets of properties represented by an object's elements and slots
   1.109 + * are disjoint. The elements contain only indexed properties, while the slots
   1.110 + * can contain both named and indexed properties; any indexes in the slots are
   1.111 + * distinct from those in the elements. If isIndexed() is false for an object,
   1.112 + * all indexed properties (if any) are stored in the dense elements.
   1.113 + *
   1.114 + * Indexes will be stored in the object's slots instead of its elements in
   1.115 + * the following case:
   1.116 + *  - there are more than MIN_SPARSE_INDEX slots total and the load factor
   1.117 + *    (COUNT / capacity) is less than 0.25
   1.118 + *  - a property is defined that has non-default property attributes.
   1.119 + *
   1.120 + * We track these pieces of metadata for dense elements:
   1.121 + *  - The length property as a uint32_t, accessible for array objects with
   1.122 + *    ArrayObject::{length,setLength}().  This is unused for non-arrays.
   1.123 + *  - The number of element slots (capacity), gettable with
   1.124 + *    getDenseElementsCapacity().
   1.125 + *  - The array's initialized length, accessible with
   1.126 + *    getDenseElementsInitializedLength().
   1.127 + *
   1.128 + * Holes in the array are represented by MagicValue(JS_ELEMENTS_HOLE) values.
   1.129 + * These indicate indexes which are not dense properties of the array. The
   1.130 + * property may, however, be held by the object's properties.
   1.131 + *
   1.132 + * The capacity and length of an object's elements are almost entirely
   1.133 + * unrelated!  In general the length may be greater than, less than, or equal
   1.134 + * to the capacity.  The first case occurs with |new Array(100)|.  The length
   1.135 + * is 100, but the capacity remains 0 (indices below length and above capacity
   1.136 + * must be treated as holes) until elements between capacity and length are
   1.137 + * set.  The other two cases are common, depending upon the number of elements
   1.138 + * in an array and the underlying allocator used for element storage.
   1.139 + *
   1.140 + * The only case in which the capacity and length of an object's elements are
   1.141 + * related is when the object is an array with non-writable length.  In this
   1.142 + * case the capacity is always less than or equal to the length.  This permits
   1.143 + * JIT code to optimize away the check for non-writable length when assigning
   1.144 + * to possibly out-of-range elements: such code already has to check for
   1.145 + * |index < capacity|, and fallback code checks for non-writable length.
   1.146 + *
   1.147 + * The initialized length of an object specifies the number of elements that
   1.148 + * have been initialized. All elements above the initialized length are
   1.149 + * holes in the object, and the memory for all elements between the initialized
   1.150 + * length and capacity is left uninitialized. The initialized length is some
   1.151 + * value less than or equal to both the object's length and the object's
   1.152 + * capacity.
   1.153 + *
   1.154 + * There is flexibility in exactly the value the initialized length must hold,
   1.155 + * e.g. if an array has length 5, capacity 10, completely empty, it is valid
   1.156 + * for the initialized length to be any value between zero and 5, as long as
   1.157 + * the in memory values below the initialized length have been initialized with
   1.158 + * a hole value. However, in such cases we want to keep the initialized length
   1.159 + * as small as possible: if the object is known to have no hole values below
   1.160 + * its initialized length, then it is "packed" and can be accessed much faster
   1.161 + * by JIT code.
   1.162 + *
   1.163 + * Elements do not track property creation order, so enumerating the elements
   1.164 + * of an object does not necessarily visit indexes in the order they were
   1.165 + * created.
   1.166 + */
   1.167 +class ObjectElements
   1.168 +{
   1.169 +  public:
   1.170 +    enum Flags {
   1.171 +        CONVERT_DOUBLE_ELEMENTS     = 0x1,
   1.172 +
   1.173 +        // Present only if these elements correspond to an array with
   1.174 +        // non-writable length; never present for non-arrays.
   1.175 +        NONWRITABLE_ARRAY_LENGTH    = 0x2
   1.176 +    };
   1.177 +
   1.178 +  private:
   1.179 +    friend class ::JSObject;
   1.180 +    friend class ObjectImpl;
   1.181 +    friend class ArrayObject;
   1.182 +    friend class Nursery;
   1.183 +
   1.184 +    template <ExecutionMode mode>
   1.185 +    friend bool
   1.186 +    ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
   1.187 +                   Handle<ArrayObject*> obj, HandleId id,
   1.188 +                   unsigned attrs, HandleValue value, bool setterIsStrict);
   1.189 +
   1.190 +    /* See Flags enum above. */
   1.191 +    uint32_t flags;
   1.192 +
   1.193 +    /*
   1.194 +     * Number of initialized elements. This is <= the capacity, and for arrays
   1.195 +     * is <= the length. Memory for elements above the initialized length is
   1.196 +     * uninitialized, but values between the initialized length and the proper
   1.197 +     * length are conceptually holes.
   1.198 +     */
   1.199 +    uint32_t initializedLength;
   1.200 +
   1.201 +    /* Number of allocated slots. */
   1.202 +    uint32_t capacity;
   1.203 +
   1.204 +    /* 'length' property of array objects, unused for other objects. */
   1.205 +    uint32_t length;
   1.206 +
   1.207 +    void staticAsserts() {
   1.208 +        static_assert(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
   1.209 +                      "Elements size and values-per-Elements mismatch");
   1.210 +    }
   1.211 +
   1.212 +    bool shouldConvertDoubleElements() const {
   1.213 +        return flags & CONVERT_DOUBLE_ELEMENTS;
   1.214 +    }
   1.215 +    void setShouldConvertDoubleElements() {
   1.216 +        flags |= CONVERT_DOUBLE_ELEMENTS;
   1.217 +    }
   1.218 +    void clearShouldConvertDoubleElements() {
   1.219 +        flags &= ~CONVERT_DOUBLE_ELEMENTS;
   1.220 +    }
   1.221 +    bool hasNonwritableArrayLength() const {
   1.222 +        return flags & NONWRITABLE_ARRAY_LENGTH;
   1.223 +    }
   1.224 +    void setNonwritableArrayLength() {
   1.225 +        flags |= NONWRITABLE_ARRAY_LENGTH;
   1.226 +    }
   1.227 +
   1.228 +  public:
   1.229 +    MOZ_CONSTEXPR ObjectElements(uint32_t capacity, uint32_t length)
   1.230 +      : flags(0), initializedLength(0), capacity(capacity), length(length)
   1.231 +    {}
   1.232 +
   1.233 +    HeapSlot *elements() {
   1.234 +        return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
   1.235 +    }
   1.236 +    static ObjectElements * fromElements(HeapSlot *elems) {
   1.237 +        return reinterpret_cast<ObjectElements*>(uintptr_t(elems) - sizeof(ObjectElements));
   1.238 +    }
   1.239 +
   1.240 +    static int offsetOfFlags() {
   1.241 +        return int(offsetof(ObjectElements, flags)) - int(sizeof(ObjectElements));
   1.242 +    }
   1.243 +    static int offsetOfInitializedLength() {
   1.244 +        return int(offsetof(ObjectElements, initializedLength)) - int(sizeof(ObjectElements));
   1.245 +    }
   1.246 +    static int offsetOfCapacity() {
   1.247 +        return int(offsetof(ObjectElements, capacity)) - int(sizeof(ObjectElements));
   1.248 +    }
   1.249 +    static int offsetOfLength() {
   1.250 +        return int(offsetof(ObjectElements, length)) - int(sizeof(ObjectElements));
   1.251 +    }
   1.252 +
   1.253 +    static bool ConvertElementsToDoubles(JSContext *cx, uintptr_t elements);
   1.254 +
   1.255 +    static const size_t VALUES_PER_HEADER = 2;
   1.256 +};
   1.257 +
   1.258 +/* Shared singleton for objects with no elements. */
   1.259 +extern HeapSlot *const emptyObjectElements;
   1.260 +
   1.261 +struct Class;
   1.262 +struct GCMarker;
   1.263 +struct ObjectOps;
   1.264 +class Shape;
   1.265 +
   1.266 +class NewObjectCache;
   1.267 +class TaggedProto;
   1.268 +
   1.269 +inline Value
   1.270 +ObjectValue(ObjectImpl &obj);
   1.271 +
   1.272 +#ifdef DEBUG
   1.273 +static inline bool
   1.274 +IsObjectValueInCompartment(js::Value v, JSCompartment *comp);
   1.275 +#endif
   1.276 +
   1.277 +/*
   1.278 + * ObjectImpl specifies the internal implementation of an object.  (In contrast
   1.279 + * JSObject specifies an "external" interface, at the conceptual level of that
   1.280 + * exposed in ECMAScript.)
   1.281 + *
   1.282 + * The |shape_| member stores the shape of the object, which includes the
   1.283 + * object's class and the layout of all its properties.
   1.284 + *
   1.285 + * The |type_| member stores the type of the object, which contains its
   1.286 + * prototype object and the possible types of its properties.
   1.287 + *
   1.288 + * The rest of the object stores its named properties and indexed elements.
   1.289 + * These are stored separately from one another. Objects are followed by a
   1.290 + * variable-sized array of values for inline storage, which may be used by
   1.291 + * either properties of native objects (fixed slots), by elements (fixed
   1.292 + * elements), or by other data for certain kinds of objects, such as
   1.293 + * ArrayBufferObjects and TypedArrayObjects.
   1.294 + *
   1.295 + * Two native objects with the same shape are guaranteed to have the same
   1.296 + * number of fixed slots.
   1.297 + *
   1.298 + * Named property storage can be split between fixed slots and a dynamically
   1.299 + * allocated array (the slots member). For an object with N fixed slots, shapes
   1.300 + * with slots [0..N-1] are stored in the fixed slots, and the remainder are
   1.301 + * stored in the dynamic array. If all properties fit in the fixed slots, the
   1.302 + * 'slots' member is nullptr.
   1.303 + *
   1.304 + * Elements are indexed via the 'elements' member. This member can point to
   1.305 + * either the shared emptyObjectElements singleton, into the inline value array
   1.306 + * (the address of the third value, to leave room for a ObjectElements header;
   1.307 + * in this case numFixedSlots() is zero) or to a dynamically allocated array.
   1.308 + *
   1.309 + * Only certain combinations of slots and elements storage are possible.
   1.310 + *
   1.311 + * - For native objects, slots and elements may both be non-empty. The
   1.312 + *   slots may be either names or indexes; no indexed property will be in both
   1.313 + *   the slots and elements.
   1.314 + *
   1.315 + * - For non-native objects, slots and elements are both empty.
   1.316 + *
   1.317 + * The members of this class are currently protected; in the long run this will
   1.318 + * will change so that some members are private, and only certain methods that
   1.319 + * act upon them will be protected.
   1.320 + */
   1.321 +class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
   1.322 +{
   1.323 +    friend Zone *js::gc::BarrieredCell<ObjectImpl>::zone() const;
   1.324 +    friend Zone *js::gc::BarrieredCell<ObjectImpl>::zoneFromAnyThread() const;
   1.325 +
   1.326 +  protected:
   1.327 +    /*
   1.328 +     * Shape of the object, encodes the layout of the object's properties and
   1.329 +     * all other information about its structure. See vm/Shape.h.
   1.330 +     */
   1.331 +    HeapPtrShape shape_;
   1.332 +
   1.333 +    /*
   1.334 +     * The object's type and prototype. For objects with the LAZY_TYPE flag
   1.335 +     * set, this is the prototype's default 'new' type and can only be used
   1.336 +     * to get that prototype.
   1.337 +     */
   1.338 +    HeapPtrTypeObject type_;
   1.339 +
   1.340 +    HeapSlot *slots;     /* Slots for object properties. */
   1.341 +    HeapSlot *elements;  /* Slots for object elements. */
   1.342 +
   1.343 +    friend bool
   1.344 +    ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id, unsigned attrs,
   1.345 +                   HandleValue value, bool setterIsStrict);
   1.346 +
   1.347 +  private:
   1.348 +    static void staticAsserts() {
   1.349 +        static_assert(sizeof(ObjectImpl) == sizeof(shadow::Object),
   1.350 +                      "shadow interface must match actual implementation");
   1.351 +        static_assert(sizeof(ObjectImpl) % sizeof(Value) == 0,
   1.352 +                      "fixed slots after an object must be aligned");
   1.353 +
   1.354 +        static_assert(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
   1.355 +                      "shadow shape must match actual shape");
   1.356 +        static_assert(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
   1.357 +                      "shadow type must match actual type");
   1.358 +        static_assert(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
   1.359 +                      "shadow slots must match actual slots");
   1.360 +        static_assert(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
   1.361 +                      "shadow placeholder must match actual elements");
   1.362 +    }
   1.363 +
   1.364 +    JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
   1.365 +    const JSObject * asObjectPtr() const { return reinterpret_cast<const JSObject *>(this); }
   1.366 +
   1.367 +    friend inline Value ObjectValue(ObjectImpl &obj);
   1.368 +
   1.369 +    /* These functions are public, and they should remain public. */
   1.370 +
   1.371 +  public:
   1.372 +    TaggedProto getTaggedProto() const {
   1.373 +        return type_->proto();
   1.374 +    }
   1.375 +
   1.376 +    bool hasTenuredProto() const;
   1.377 +
   1.378 +    const Class *getClass() const {
   1.379 +        return type_->clasp();
   1.380 +    }
   1.381 +
   1.382 +    static inline bool
   1.383 +    isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible);
   1.384 +
   1.385 +    // Indicates whether a non-proxy is extensible.  Don't call on proxies!
   1.386 +    // This method really shouldn't exist -- but there are a few internal
   1.387 +    // places that want it (JITs and the like), and it'd be a pain to mark them
   1.388 +    // all as friends.
   1.389 +    bool nonProxyIsExtensible() const {
   1.390 +        MOZ_ASSERT(!isProxy());
   1.391 +
   1.392 +        // [[Extensible]] for ordinary non-proxy objects is an object flag.
   1.393 +        return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE);
   1.394 +    }
   1.395 +
   1.396 +#ifdef DEBUG
   1.397 +    bool isProxy() const;
   1.398 +#endif
   1.399 +
   1.400 +    // Attempt to change the [[Extensible]] bit on |obj| to false.  Callers
   1.401 +    // must ensure that |obj| is currently extensible before calling this!
   1.402 +    static bool
   1.403 +    preventExtensions(JSContext *cx, Handle<ObjectImpl*> obj);
   1.404 +
   1.405 +    HeapSlotArray getDenseElements() {
   1.406 +        JS_ASSERT(isNative());
   1.407 +        return HeapSlotArray(elements);
   1.408 +    }
   1.409 +    const Value &getDenseElement(uint32_t idx) {
   1.410 +        JS_ASSERT(isNative());
   1.411 +        MOZ_ASSERT(idx < getDenseInitializedLength());
   1.412 +        return elements[idx];
   1.413 +    }
   1.414 +    bool containsDenseElement(uint32_t idx) {
   1.415 +        JS_ASSERT(isNative());
   1.416 +        return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE);
   1.417 +    }
   1.418 +    uint32_t getDenseInitializedLength() {
   1.419 +        JS_ASSERT(getClass()->isNative());
   1.420 +        return getElementsHeader()->initializedLength;
   1.421 +    }
   1.422 +    uint32_t getDenseCapacity() {
   1.423 +        JS_ASSERT(getClass()->isNative());
   1.424 +        return getElementsHeader()->capacity;
   1.425 +    }
   1.426 +
   1.427 +  protected:
   1.428 +#ifdef DEBUG
   1.429 +    void checkShapeConsistency();
   1.430 +#else
   1.431 +    void checkShapeConsistency() { }
   1.432 +#endif
   1.433 +
   1.434 +    Shape *
   1.435 +    replaceWithNewEquivalentShape(ThreadSafeContext *cx,
   1.436 +                                  Shape *existingShape, Shape *newShape = nullptr);
   1.437 +
   1.438 +    enum GenerateShape {
   1.439 +        GENERATE_NONE,
   1.440 +        GENERATE_SHAPE
   1.441 +    };
   1.442 +
   1.443 +    bool setFlag(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flag,
   1.444 +                 GenerateShape generateShape = GENERATE_NONE);
   1.445 +    bool clearFlag(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flag);
   1.446 +
   1.447 +    bool toDictionaryMode(ThreadSafeContext *cx);
   1.448 +
   1.449 +  private:
   1.450 +    friend class Nursery;
   1.451 +
   1.452 +    /*
   1.453 +     * Get internal pointers to the range of values starting at start and
   1.454 +     * running for length.
   1.455 +     */
   1.456 +    void getSlotRangeUnchecked(uint32_t start, uint32_t length,
   1.457 +                               HeapSlot **fixedStart, HeapSlot **fixedEnd,
   1.458 +                               HeapSlot **slotsStart, HeapSlot **slotsEnd)
   1.459 +    {
   1.460 +        MOZ_ASSERT(start + length >= start);
   1.461 +
   1.462 +        uint32_t fixed = numFixedSlots();
   1.463 +        if (start < fixed) {
   1.464 +            if (start + length < fixed) {
   1.465 +                *fixedStart = &fixedSlots()[start];
   1.466 +                *fixedEnd = &fixedSlots()[start + length];
   1.467 +                *slotsStart = *slotsEnd = nullptr;
   1.468 +            } else {
   1.469 +                uint32_t localCopy = fixed - start;
   1.470 +                *fixedStart = &fixedSlots()[start];
   1.471 +                *fixedEnd = &fixedSlots()[start + localCopy];
   1.472 +                *slotsStart = &slots[0];
   1.473 +                *slotsEnd = &slots[length - localCopy];
   1.474 +            }
   1.475 +        } else {
   1.476 +            *fixedStart = *fixedEnd = nullptr;
   1.477 +            *slotsStart = &slots[start - fixed];
   1.478 +            *slotsEnd = &slots[start - fixed + length];
   1.479 +        }
   1.480 +    }
   1.481 +
   1.482 +    void getSlotRange(uint32_t start, uint32_t length,
   1.483 +                      HeapSlot **fixedStart, HeapSlot **fixedEnd,
   1.484 +                      HeapSlot **slotsStart, HeapSlot **slotsEnd)
   1.485 +    {
   1.486 +        MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
   1.487 +        getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
   1.488 +    }
   1.489 +
   1.490 +  protected:
   1.491 +    friend struct GCMarker;
   1.492 +    friend class Shape;
   1.493 +    friend class NewObjectCache;
   1.494 +
   1.495 +    void invalidateSlotRange(uint32_t start, uint32_t length) {
   1.496 +#ifdef DEBUG
   1.497 +        HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
   1.498 +        getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
   1.499 +        Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
   1.500 +        Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
   1.501 +#endif /* DEBUG */
   1.502 +    }
   1.503 +
   1.504 +    void initializeSlotRange(uint32_t start, uint32_t count);
   1.505 +
   1.506 +    /*
   1.507 +     * Initialize a flat array of slots to this object at a start slot.  The
   1.508 +     * caller must ensure that are enough slots.
   1.509 +     */
   1.510 +    void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
   1.511 +
   1.512 +    /*
   1.513 +     * Copy a flat array of slots to this object at a start slot. Caller must
   1.514 +     * ensure there are enough slots in this object.
   1.515 +     */
   1.516 +    void copySlotRange(uint32_t start, const Value *vector, uint32_t length);
   1.517 +
   1.518 +#ifdef DEBUG
   1.519 +    enum SentinelAllowed {
   1.520 +        SENTINEL_NOT_ALLOWED,
   1.521 +        SENTINEL_ALLOWED
   1.522 +    };
   1.523 +
   1.524 +    /*
   1.525 +     * Check that slot is in range for the object's allocated slots.
   1.526 +     * If sentinelAllowed then slot may equal the slot capacity.
   1.527 +     */
   1.528 +    bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
   1.529 +#endif
   1.530 +
   1.531 +    /*
   1.532 +     * Minimum size for dynamically allocated slots in normal Objects.
   1.533 +     * ArrayObjects don't use this limit and can have a lower slot capacity,
   1.534 +     * since they normally don't have a lot of slots.
   1.535 +     */
   1.536 +    static const uint32_t SLOT_CAPACITY_MIN = 8;
   1.537 +
   1.538 +    HeapSlot *fixedSlots() const {
   1.539 +        return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
   1.540 +    }
   1.541 +
   1.542 +    /*
   1.543 +     * These functions are currently public for simplicity; in the long run
   1.544 +     * it may make sense to make at least some of them private.
   1.545 +     */
   1.546 +
   1.547 +  public:
   1.548 +    Shape * lastProperty() const {
   1.549 +        MOZ_ASSERT(shape_);
   1.550 +        return shape_;
   1.551 +    }
   1.552 +
   1.553 +    bool generateOwnShape(ThreadSafeContext *cx, js::Shape *newShape = nullptr) {
   1.554 +        return replaceWithNewEquivalentShape(cx, lastProperty(), newShape);
   1.555 +    }
   1.556 +
   1.557 +    JSCompartment *compartment() const {
   1.558 +        return lastProperty()->base()->compartment();
   1.559 +    }
   1.560 +
   1.561 +    bool isNative() const {
   1.562 +        return lastProperty()->isNative();
   1.563 +    }
   1.564 +
   1.565 +    types::TypeObject *type() const {
   1.566 +        MOZ_ASSERT(!hasLazyType());
   1.567 +        return typeRaw();
   1.568 +    }
   1.569 +
   1.570 +    types::TypeObject *typeRaw() const {
   1.571 +        return type_;
   1.572 +    }
   1.573 +
   1.574 +    uint32_t numFixedSlots() const {
   1.575 +        return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
   1.576 +    }
   1.577 +
   1.578 +    /*
   1.579 +     * Whether this is the only object which has its specified type. This
   1.580 +     * object will have its type constructed lazily as needed by analysis.
   1.581 +     */
   1.582 +    bool hasSingletonType() const {
   1.583 +        return !!type_->singleton();
   1.584 +    }
   1.585 +
   1.586 +    /*
   1.587 +     * Whether the object's type has not been constructed yet. If an object
   1.588 +     * might have a lazy type, use getType() below, otherwise type().
   1.589 +     */
   1.590 +    bool hasLazyType() const {
   1.591 +        return type_->lazy();
   1.592 +    }
   1.593 +
   1.594 +    uint32_t slotSpan() const {
   1.595 +        if (inDictionaryMode())
   1.596 +            return lastProperty()->base()->slotSpan();
   1.597 +        return lastProperty()->slotSpan();
   1.598 +    }
   1.599 +
   1.600 +    /* Compute dynamicSlotsCount() for this object. */
   1.601 +    uint32_t numDynamicSlots() const {
   1.602 +        return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
   1.603 +    }
   1.604 +
   1.605 +
   1.606 +    Shape *nativeLookup(ExclusiveContext *cx, jsid id);
   1.607 +    Shape *nativeLookup(ExclusiveContext *cx, PropertyName *name) {
   1.608 +        return nativeLookup(cx, NameToId(name));
   1.609 +    }
   1.610 +
   1.611 +    bool nativeContains(ExclusiveContext *cx, jsid id) {
   1.612 +        return nativeLookup(cx, id) != nullptr;
   1.613 +    }
   1.614 +    bool nativeContains(ExclusiveContext *cx, PropertyName* name) {
   1.615 +        return nativeLookup(cx, name) != nullptr;
   1.616 +    }
   1.617 +    bool nativeContains(ExclusiveContext *cx, Shape* shape) {
   1.618 +        return nativeLookup(cx, shape->propid()) == shape;
   1.619 +    }
   1.620 +
   1.621 +    /* Contextless; can be called from parallel code. */
   1.622 +    Shape *nativeLookupPure(jsid id);
   1.623 +    Shape *nativeLookupPure(PropertyName *name) {
   1.624 +        return nativeLookupPure(NameToId(name));
   1.625 +    }
   1.626 +
   1.627 +    bool nativeContainsPure(jsid id) {
   1.628 +        return nativeLookupPure(id) != nullptr;
   1.629 +    }
   1.630 +    bool nativeContainsPure(PropertyName* name) {
   1.631 +        return nativeContainsPure(NameToId(name));
   1.632 +    }
   1.633 +    bool nativeContainsPure(Shape* shape) {
   1.634 +        return nativeLookupPure(shape->propid()) == shape;
   1.635 +    }
   1.636 +
   1.637 +    const JSClass *getJSClass() const {
   1.638 +        return Jsvalify(getClass());
   1.639 +    }
   1.640 +    bool hasClass(const Class *c) const {
   1.641 +        return getClass() == c;
   1.642 +    }
   1.643 +    const ObjectOps *getOps() const {
   1.644 +        return &getClass()->ops;
   1.645 +    }
   1.646 +
   1.647 +    /*
   1.648 +     * An object is a delegate if it is on another object's prototype or scope
   1.649 +     * chain, and therefore the delegate might be asked implicitly to get or
   1.650 +     * set a property on behalf of another object. Delegates may be accessed
   1.651 +     * directly too, as may any object, but only those objects linked after the
   1.652 +     * head of any prototype or scope chain are flagged as delegates. This
   1.653 +     * definition helps to optimize shape-based property cache invalidation
   1.654 +     * (see Purge{Scope,Proto}Chain in jsobj.cpp).
   1.655 +     */
   1.656 +    bool isDelegate() const {
   1.657 +        return lastProperty()->hasObjectFlag(BaseShape::DELEGATE);
   1.658 +    }
   1.659 +
   1.660 +    /*
   1.661 +     * Return true if this object is a native one that has been converted from
   1.662 +     * shared-immutable prototype-rooted shape storage to dictionary-shapes in
   1.663 +     * a doubly-linked list.
   1.664 +     */
   1.665 +    bool inDictionaryMode() const {
   1.666 +        return lastProperty()->inDictionary();
   1.667 +    }
   1.668 +
   1.669 +    const Value &getSlot(uint32_t slot) const {
   1.670 +        MOZ_ASSERT(slotInRange(slot));
   1.671 +        uint32_t fixed = numFixedSlots();
   1.672 +        if (slot < fixed)
   1.673 +            return fixedSlots()[slot];
   1.674 +        return slots[slot - fixed];
   1.675 +    }
   1.676 +
   1.677 +    const HeapSlot *getSlotAddressUnchecked(uint32_t slot) const {
   1.678 +        uint32_t fixed = numFixedSlots();
   1.679 +        if (slot < fixed)
   1.680 +            return fixedSlots() + slot;
   1.681 +        return slots + (slot - fixed);
   1.682 +    }
   1.683 +
   1.684 +    HeapSlot *getSlotAddressUnchecked(uint32_t slot) {
   1.685 +        const ObjectImpl *obj = static_cast<const ObjectImpl*>(this);
   1.686 +        return const_cast<HeapSlot*>(obj->getSlotAddressUnchecked(slot));
   1.687 +    }
   1.688 +
   1.689 +    HeapSlot *getSlotAddress(uint32_t slot) {
   1.690 +        /*
   1.691 +         * This can be used to get the address of the end of the slots for the
   1.692 +         * object, which may be necessary when fetching zero-length arrays of
   1.693 +         * slots (e.g. for callObjVarArray).
   1.694 +         */
   1.695 +        MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
   1.696 +        return getSlotAddressUnchecked(slot);
   1.697 +    }
   1.698 +
   1.699 +    const HeapSlot *getSlotAddress(uint32_t slot) const {
   1.700 +        /*
   1.701 +         * This can be used to get the address of the end of the slots for the
   1.702 +         * object, which may be necessary when fetching zero-length arrays of
   1.703 +         * slots (e.g. for callObjVarArray).
   1.704 +         */
   1.705 +        MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
   1.706 +        return getSlotAddressUnchecked(slot);
   1.707 +    }
   1.708 +
   1.709 +    HeapSlot &getSlotRef(uint32_t slot) {
   1.710 +        MOZ_ASSERT(slotInRange(slot));
   1.711 +        return *getSlotAddress(slot);
   1.712 +    }
   1.713 +
   1.714 +    const HeapSlot &getSlotRef(uint32_t slot) const {
   1.715 +        MOZ_ASSERT(slotInRange(slot));
   1.716 +        return *getSlotAddress(slot);
   1.717 +    }
   1.718 +
   1.719 +    HeapSlot &nativeGetSlotRef(uint32_t slot) {
   1.720 +        JS_ASSERT(isNative() && slot < slotSpan());
   1.721 +        return getSlotRef(slot);
   1.722 +    }
   1.723 +    const Value &nativeGetSlot(uint32_t slot) const {
   1.724 +        JS_ASSERT(isNative() && slot < slotSpan());
   1.725 +        return getSlot(slot);
   1.726 +    }
   1.727 +
   1.728 +    void setSlot(uint32_t slot, const Value &value) {
   1.729 +        MOZ_ASSERT(slotInRange(slot));
   1.730 +        MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
   1.731 +        getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
   1.732 +    }
   1.733 +
   1.734 +    inline void setCrossCompartmentSlot(uint32_t slot, const Value &value) {
   1.735 +        MOZ_ASSERT(slotInRange(slot));
   1.736 +        getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
   1.737 +    }
   1.738 +
   1.739 +    void initSlot(uint32_t slot, const Value &value) {
   1.740 +        MOZ_ASSERT(getSlot(slot).isUndefined());
   1.741 +        MOZ_ASSERT(slotInRange(slot));
   1.742 +        MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
   1.743 +        initSlotUnchecked(slot, value);
   1.744 +    }
   1.745 +
   1.746 +    void initCrossCompartmentSlot(uint32_t slot, const Value &value) {
   1.747 +        MOZ_ASSERT(getSlot(slot).isUndefined());
   1.748 +        MOZ_ASSERT(slotInRange(slot));
   1.749 +        initSlotUnchecked(slot, value);
   1.750 +    }
   1.751 +
   1.752 +    void initSlotUnchecked(uint32_t slot, const Value &value) {
   1.753 +        getSlotAddressUnchecked(slot)->init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
   1.754 +    }
   1.755 +
   1.756 +    /* For slots which are known to always be fixed, due to the way they are allocated. */
   1.757 +
   1.758 +    HeapSlot &getFixedSlotRef(uint32_t slot) {
   1.759 +        MOZ_ASSERT(slot < numFixedSlots());
   1.760 +        return fixedSlots()[slot];
   1.761 +    }
   1.762 +
   1.763 +    const Value &getFixedSlot(uint32_t slot) const {
   1.764 +        MOZ_ASSERT(slot < numFixedSlots());
   1.765 +        return fixedSlots()[slot];
   1.766 +    }
   1.767 +
   1.768 +    void setFixedSlot(uint32_t slot, const Value &value) {
   1.769 +        MOZ_ASSERT(slot < numFixedSlots());
   1.770 +        fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
   1.771 +    }
   1.772 +
   1.773 +    void initFixedSlot(uint32_t slot, const Value &value) {
   1.774 +        MOZ_ASSERT(slot < numFixedSlots());
   1.775 +        fixedSlots()[slot].init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
   1.776 +    }
   1.777 +
   1.778 +    /*
   1.779 +     * Get the number of dynamic slots to allocate to cover the properties in
   1.780 +     * an object with the given number of fixed slots and slot span. The slot
   1.781 +     * capacity is not stored explicitly, and the allocated size of the slot
   1.782 +     * array is kept in sync with this count.
   1.783 +     */
   1.784 +    static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp);
   1.785 +
   1.786 +    /* Memory usage functions. */
   1.787 +    size_t tenuredSizeOfThis() const {
   1.788 +        return js::gc::Arena::thingSize(tenuredGetAllocKind());
   1.789 +    }
   1.790 +
   1.791 +    /* Elements accessors. */
   1.792 +
   1.793 +    ObjectElements * getElementsHeader() const {
   1.794 +        return ObjectElements::fromElements(elements);
   1.795 +    }
   1.796 +
   1.797 +    inline HeapSlot *fixedElements() const {
   1.798 +        static_assert(2 * sizeof(Value) == sizeof(ObjectElements),
   1.799 +                      "when elements are stored inline, the first two "
   1.800 +                      "slots will hold the ObjectElements header");
   1.801 +        return &fixedSlots()[2];
   1.802 +    }
   1.803 +
   1.804 +#ifdef DEBUG
   1.805 +    bool canHaveNonEmptyElements();
   1.806 +#endif
   1.807 +
   1.808 +    void setFixedElements() {
   1.809 +        JS_ASSERT(canHaveNonEmptyElements());
   1.810 +        this->elements = fixedElements();
   1.811 +    }
   1.812 +
   1.813 +    inline bool hasDynamicElements() const {
   1.814 +        /*
   1.815 +         * Note: for objects with zero fixed slots this could potentially give
   1.816 +         * a spurious 'true' result, if the end of this object is exactly
   1.817 +         * aligned with the end of its arena and dynamic slots are allocated
   1.818 +         * immediately afterwards. Such cases cannot occur for dense arrays
   1.819 +         * (which have at least two fixed slots) and can only result in a leak.
   1.820 +         */
   1.821 +        return !hasEmptyElements() && elements != fixedElements();
   1.822 +    }
   1.823 +
   1.824 +    inline bool hasFixedElements() const {
   1.825 +        return elements == fixedElements();
   1.826 +    }
   1.827 +
   1.828 +    inline bool hasEmptyElements() const {
   1.829 +        return elements == emptyObjectElements;
   1.830 +    }
   1.831 +
   1.832 +    /*
   1.833 +     * Get a pointer to the unused data in the object's allocation immediately
   1.834 +     * following this object, for use with objects which allocate a larger size
   1.835 +     * class than they need and store non-elements data inline.
   1.836 +     */
   1.837 +    inline void *fixedData(size_t nslots) const;
   1.838 +
   1.839 +    /* GC support. */
   1.840 +    static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
   1.841 +
   1.842 +    inline void privateWriteBarrierPre(void **oldval);
   1.843 +
   1.844 +    void privateWriteBarrierPost(void **pprivate) {
   1.845 +#ifdef JSGC_GENERATIONAL
   1.846 +        shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
   1.847 +#endif
   1.848 +    }
   1.849 +
   1.850 +    void markChildren(JSTracer *trc);
   1.851 +
   1.852 +    /* Private data accessors. */
   1.853 +
   1.854 +    inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
   1.855 +        /*
   1.856 +         * The private pointer of an object can hold any word sized value.
   1.857 +         * Private pointers are stored immediately after the last fixed slot of
   1.858 +         * the object.
   1.859 +         */
   1.860 +        MOZ_ASSERT(nfixed == numFixedSlots());
   1.861 +        MOZ_ASSERT(hasPrivate());
   1.862 +        HeapSlot *end = &fixedSlots()[nfixed];
   1.863 +        return *reinterpret_cast<void**>(end);
   1.864 +    }
   1.865 +
   1.866 +    bool hasPrivate() const {
   1.867 +        return getClass()->hasPrivate();
   1.868 +    }
   1.869 +    void *getPrivate() const {
   1.870 +        return privateRef(numFixedSlots());
   1.871 +    }
   1.872 +    void setPrivate(void *data) {
   1.873 +        void **pprivate = &privateRef(numFixedSlots());
   1.874 +        privateWriteBarrierPre(pprivate);
   1.875 +        *pprivate = data;
   1.876 +    }
   1.877 +
   1.878 +    void setPrivateGCThing(gc::Cell *cell) {
   1.879 +        void **pprivate = &privateRef(numFixedSlots());
   1.880 +        privateWriteBarrierPre(pprivate);
   1.881 +        *pprivate = reinterpret_cast<void *>(cell);
   1.882 +        privateWriteBarrierPost(pprivate);
   1.883 +    }
   1.884 +
   1.885 +    void setPrivateUnbarriered(void *data) {
   1.886 +        void **pprivate = &privateRef(numFixedSlots());
   1.887 +        *pprivate = data;
   1.888 +    }
   1.889 +    void initPrivate(void *data) {
   1.890 +        privateRef(numFixedSlots()) = data;
   1.891 +    }
   1.892 +
   1.893 +    /* Access private data for an object with a known number of fixed slots. */
   1.894 +    inline void *getPrivate(uint32_t nfixed) const {
   1.895 +        return privateRef(nfixed);
   1.896 +    }
   1.897 +
   1.898 +    /* GC Accessors */
   1.899 +    void setInitialSlots(HeapSlot *newSlots) { slots = newSlots; }
   1.900 +
   1.901 +    /* JIT Accessors */
   1.902 +    static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
   1.903 +    HeapPtrShape *addressOfShape() { return &shape_; }
   1.904 +
   1.905 +    static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
   1.906 +    HeapPtrTypeObject *addressOfType() { return &type_; }
   1.907 +
   1.908 +    static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
   1.909 +    static size_t offsetOfFixedElements() {
   1.910 +        return sizeof(ObjectImpl) + sizeof(ObjectElements);
   1.911 +    }
   1.912 +
   1.913 +    static size_t getFixedSlotOffset(size_t slot) {
   1.914 +        return sizeof(ObjectImpl) + slot * sizeof(Value);
   1.915 +    }
   1.916 +    static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
   1.917 +    static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
   1.918 +};
   1.919 +
   1.920 +namespace gc {
   1.921 +
   1.922 +template <>
   1.923 +MOZ_ALWAYS_INLINE Zone *
   1.924 +BarrieredCell<ObjectImpl>::zone() const
   1.925 +{
   1.926 +    const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
   1.927 +    JS::Zone *zone = obj->shape_->zone();
   1.928 +    JS_ASSERT(CurrentThreadCanAccessZone(zone));
   1.929 +    return zone;
   1.930 +}
   1.931 +
   1.932 +template <>
   1.933 +MOZ_ALWAYS_INLINE Zone *
   1.934 +BarrieredCell<ObjectImpl>::zoneFromAnyThread() const
   1.935 +{
   1.936 +    const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
   1.937 +    return obj->shape_->zoneFromAnyThread();
   1.938 +}
   1.939 +
   1.940 +// TypeScript::global uses 0x1 as a special value.
   1.941 +template<>
   1.942 +/* static */ inline bool
   1.943 +BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
   1.944 +{
   1.945 +    return IsNullTaggedPointer(obj);
   1.946 +}
   1.947 +
   1.948 +template<>
   1.949 +/* static */ inline void
   1.950 +BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *addr)
   1.951 +{
   1.952 +#ifdef JSGC_GENERATIONAL
   1.953 +    if (IsNullTaggedPointer(obj))
   1.954 +        return;
   1.955 +    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell((Cell **)addr);
   1.956 +#endif
   1.957 +}
   1.958 +
   1.959 +template<>
   1.960 +/* static */ inline void
   1.961 +BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *addr)
   1.962 +{
   1.963 +#ifdef JSGC_GENERATIONAL
   1.964 +    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putRelocatableCell((Cell **)addr);
   1.965 +#endif
   1.966 +}
   1.967 +
   1.968 +template<>
   1.969 +/* static */ inline void
   1.970 +BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *addr)
   1.971 +{
   1.972 +#ifdef JSGC_GENERATIONAL
   1.973 +    obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCell((Cell **)addr);
   1.974 +#endif
   1.975 +}
   1.976 +
   1.977 +} // namespace gc
   1.978 +
   1.979 +inline void
   1.980 +ObjectImpl::privateWriteBarrierPre(void **oldval)
   1.981 +{
   1.982 +#ifdef JSGC_INCREMENTAL
   1.983 +    JS::shadow::Zone *shadowZone = this->shadowZoneFromAnyThread();
   1.984 +    if (shadowZone->needsBarrier()) {
   1.985 +        if (*oldval && getClass()->trace)
   1.986 +            getClass()->trace(shadowZone->barrierTracer(), this->asObjectPtr());
   1.987 +    }
   1.988 +#endif
   1.989 +}
   1.990 +
   1.991 +inline Value
   1.992 +ObjectValue(ObjectImpl &obj)
   1.993 +{
   1.994 +    Value v;
   1.995 +    v.setObject(*obj.asObjectPtr());
   1.996 +    return v;
   1.997 +}
   1.998 +
   1.999 +inline Handle<JSObject*>
  1.1000 +Downcast(Handle<ObjectImpl*> obj)
  1.1001 +{
  1.1002 +    return Handle<JSObject*>::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
  1.1003 +}
  1.1004 +
  1.1005 +#ifdef DEBUG
  1.1006 +static inline bool
  1.1007 +IsObjectValueInCompartment(js::Value v, JSCompartment *comp)
  1.1008 +{
  1.1009 +    if (!v.isObject())
  1.1010 +        return true;
  1.1011 +    return reinterpret_cast<ObjectImpl*>(&v.toObject())->compartment() == comp;
  1.1012 +}
  1.1013 +#endif
  1.1014 +
  1.1015 +} /* namespace js */
  1.1016 +
  1.1017 +#endif /* vm_ObjectImpl_h */

mercurial