js/src/jsobj.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef jsobj_h
     8 #define jsobj_h
    10 /*
    11  * JS object definitions.
    12  *
    13  * A JS object consists of a possibly-shared object descriptor containing
    14  * ordered property names, called the map; and a dense vector of property
    15  * values, called slots.  The map/slot pointer pair is GC'ed, while the map
    16  * is reference counted and the slot vector is malloc'ed.
    17  */
    19 #include "mozilla/MemoryReporting.h"
    21 #include "gc/Barrier.h"
    22 #include "gc/Marking.h"
    23 #include "js/GCAPI.h"
    24 #include "vm/ObjectImpl.h"
    25 #include "vm/Shape.h"
    26 #include "vm/Xdr.h"
    28 namespace JS {
    29 struct ObjectsExtraSizes;
    30 }
    32 namespace js {
    34 class AutoPropDescArrayRooter;
    35 struct GCMarker;
    36 struct NativeIterator;
    37 class Nursery;
    38 struct StackShape;
    40 inline JSObject *
    41 CastAsObject(PropertyOp op)
    42 {
    43     return JS_FUNC_TO_DATA_PTR(JSObject *, op);
    44 }
    46 inline JSObject *
    47 CastAsObject(StrictPropertyOp op)
    48 {
    49     return JS_FUNC_TO_DATA_PTR(JSObject *, op);
    50 }
    52 inline Value
    53 CastAsObjectJsval(PropertyOp op)
    54 {
    55     return ObjectOrNullValue(CastAsObject(op));
    56 }
    58 inline Value
    59 CastAsObjectJsval(StrictPropertyOp op)
    60 {
    61     return ObjectOrNullValue(CastAsObject(op));
    62 }
    64 /******************************************************************************/
    66 typedef Vector<PropDesc, 1> PropDescArray;
    68 /*
    69  * The baseops namespace encapsulates the default behavior when performing
    70  * various operations on an object, irrespective of hooks installed in the
    71  * object's class. In general, instance methods on the object itself should be
    72  * called instead of calling these methods directly.
    73  */
    74 namespace baseops {
    76 /*
    77  * On success, and if id was found, return true with *objp non-null and with a
    78  * property of *objp stored in *propp. If successful but id was not found,
    79  * return true with both *objp and *propp null.
    80  */
    81 template <AllowGC allowGC>
    82 extern bool
    83 LookupProperty(ExclusiveContext *cx,
    84                typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
    85                typename MaybeRooted<jsid, allowGC>::HandleType id,
    86                typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
    87                typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
    89 extern bool
    90 LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
    91               MutableHandleObject objp, MutableHandleShape propp);
    93 extern bool
    94 DefineGeneric(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
    95                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
    97 extern bool
    98 DefineElement(ExclusiveContext *cx, HandleObject obj, uint32_t index, HandleValue value,
    99               JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
   101 extern bool
   102 GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, MutableHandleValue vp);
   104 extern bool
   105 GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
   107 extern bool
   108 GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp);
   110 inline bool
   111 GetProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
   112 {
   113     return GetProperty(cx, obj, obj, id, vp);
   114 }
   116 inline bool
   117 GetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
   118 {
   119     return GetElement(cx, obj, obj, index, vp);
   120 }
   122 /*
   123  * Indicates whether an assignment operation is qualified (`x.y = 0`) or
   124  * unqualified (`y = 0`). In strict mode, the latter is an error if no such
   125  * variable already exists.
   126  *
   127  * Used as an argument to baseops::SetPropertyHelper.
   128  */
   129 enum QualifiedBool {
   130     Unqualified = 0,
   131     Qualified = 1
   132 };
   134 template <ExecutionMode mode>
   135 extern bool
   136 SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cx, HandleObject obj,
   137                   HandleObject receiver, HandleId id, QualifiedBool qualified,
   138                   MutableHandleValue vp, bool strict);
   140 extern bool
   141 SetElementHelper(JSContext *cx, HandleObject obj, HandleObject Receiver, uint32_t index,
   142                  MutableHandleValue vp, bool strict);
   144 extern bool
   145 GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
   147 extern bool
   148 SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
   150 extern bool
   151 DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded);
   153 extern bool
   154 DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded);
   156 extern bool
   157 DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
   159 extern bool
   160 Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
   162 extern bool
   163 Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
   165 } /* namespace js::baseops */
   167 extern const Class IntlClass;
   168 extern const Class JSONClass;
   169 extern const Class MathClass;
   171 class GlobalObject;
   172 class MapObject;
   173 class NewObjectCache;
   174 class NormalArgumentsObject;
   175 class SetObject;
   176 class StrictArgumentsObject;
   178 /*
   179  * NOTE: This is a placeholder for bug 619558.
   180  *
   181  * Run a post write barrier that encompasses multiple contiguous slots in a
   182  * single step.
   183  */
   184 inline void
   185 DenseRangeWriteBarrierPost(JSRuntime *rt, JSObject *obj, uint32_t start, uint32_t count)
   186 {
   187 #ifdef JSGC_GENERATIONAL
   188     if (count > 0) {
   189         JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
   190         shadowRuntime->gcStoreBufferPtr()->putSlot(obj, HeapSlot::Element, start, count);
   191     }
   192 #endif
   193 }
   195 }  /* namespace js */
   197 /*
   198  * The public interface for an object.
   199  *
   200  * Implementation of the underlying structure occurs in ObjectImpl, from which
   201  * this struct inherits.  This inheritance is currently public, but it will
   202  * eventually be made protected.  For full details, see vm/ObjectImpl.{h,cpp}.
   203  *
   204  * The JSFunction struct is an extension of this struct allocated from a larger
   205  * GC size-class.
   206  */
   207 class JSObject : public js::ObjectImpl
   208 {
   209   private:
   210     friend class js::Shape;
   211     friend struct js::GCMarker;
   212     friend class  js::NewObjectCache;
   213     friend class js::Nursery;
   215     /* Make the type object to use for LAZY_TYPE objects. */
   216     static js::types::TypeObject *makeLazyType(JSContext *cx, js::HandleObject obj);
   218   public:
   219     static const js::Class class_;
   221     /*
   222      * Update the last property, keeping the number of allocated slots in sync
   223      * with the object's new slot span.
   224      */
   225     static bool setLastProperty(js::ThreadSafeContext *cx,
   226                                 JS::HandleObject obj, js::HandleShape shape);
   228     /* As above, but does not change the slot span. */
   229     inline void setLastPropertyInfallible(js::Shape *shape);
   231     /*
   232      * Make a non-array object with the specified initial state. This method
   233      * takes ownership of any extantSlots it is passed.
   234      */
   235     static inline JSObject *create(js::ExclusiveContext *cx,
   236                                    js::gc::AllocKind kind,
   237                                    js::gc::InitialHeap heap,
   238                                    js::HandleShape shape,
   239                                    js::HandleTypeObject type,
   240                                    js::HeapSlot *extantSlots = nullptr);
   242     /* Make an array object with the specified initial state. */
   243     static inline js::ArrayObject *createArray(js::ExclusiveContext *cx,
   244                                                js::gc::AllocKind kind,
   245                                                js::gc::InitialHeap heap,
   246                                                js::HandleShape shape,
   247                                                js::HandleTypeObject type,
   248                                                uint32_t length);
   250     /*
   251      * Remove the last property of an object, provided that it is safe to do so
   252      * (the shape and previous shape do not carry conflicting information about
   253      * the object itself).
   254      */
   255     inline void removeLastProperty(js::ExclusiveContext *cx);
   256     inline bool canRemoveLastProperty();
   258     /*
   259      * Update the slot span directly for a dictionary object, and allocate
   260      * slots to cover the new span if necessary.
   261      */
   262     static bool setSlotSpan(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t span);
   264     /* Upper bound on the number of elements in an object. */
   265     static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
   267   public:
   268     bool setDelegate(js::ExclusiveContext *cx) {
   269         return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
   270     }
   272     bool isBoundFunction() const {
   273         return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
   274     }
   276     inline bool hasSpecialEquality() const;
   278     bool watched() const {
   279         return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
   280     }
   281     bool setWatched(js::ExclusiveContext *cx) {
   282         return setFlag(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
   283     }
   285     /* See InterpreterFrame::varObj. */
   286     inline bool isVarObj();
   287     bool setVarObj(js::ExclusiveContext *cx) {
   288         return setFlag(cx, js::BaseShape::VAROBJ);
   289     }
   291     /*
   292      * Objects with an uncacheable proto can have their prototype mutated
   293      * without inducing a shape change on the object. Property cache entries
   294      * and JIT inline caches should not be filled for lookups across prototype
   295      * lookups on the object.
   296      */
   297     bool hasUncacheableProto() const {
   298         return lastProperty()->hasObjectFlag(js::BaseShape::UNCACHEABLE_PROTO);
   299     }
   300     bool setUncacheableProto(js::ExclusiveContext *cx) {
   301         return setFlag(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
   302     }
   304     /*
   305      * Whether SETLELEM was used to access this object. See also the comment near
   306      * PropertyTree::MAX_HEIGHT.
   307      */
   308     bool hadElementsAccess() const {
   309         return lastProperty()->hasObjectFlag(js::BaseShape::HAD_ELEMENTS_ACCESS);
   310     }
   311     bool setHadElementsAccess(js::ExclusiveContext *cx) {
   312         return setFlag(cx, js::BaseShape::HAD_ELEMENTS_ACCESS);
   313     }
   315   public:
   316     bool nativeEmpty() const {
   317         return lastProperty()->isEmptyShape();
   318     }
   320     bool shadowingShapeChange(js::ExclusiveContext *cx, const js::Shape &shape);
   322     /*
   323      * Whether there may be indexed properties on this object, excluding any in
   324      * the object's elements.
   325      */
   326     bool isIndexed() const {
   327         return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
   328     }
   330     uint32_t propertyCount() const {
   331         return lastProperty()->entryCount();
   332     }
   334     bool hasShapeTable() const {
   335         return lastProperty()->hasTable();
   336     }
   338     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes);
   340     bool hasIdempotentProtoChain() const;
   342     // MAX_FIXED_SLOTS is the biggest number of fixed slots our GC
   343     // size classes will give an object.
   344     static const uint32_t MAX_FIXED_SLOTS = 16;
   346   public:
   348     /* Accessors for properties. */
   350     /* Whether a slot is at a fixed offset from this object. */
   351     bool isFixedSlot(size_t slot) {
   352         return slot < numFixedSlots();
   353     }
   355     /* Index into the dynamic slots array to use for a dynamic slot. */
   356     size_t dynamicSlotIndex(size_t slot) {
   357         JS_ASSERT(slot >= numFixedSlots());
   358         return slot - numFixedSlots();
   359     }
   361     /*
   362      * Grow or shrink slots immediately before changing the slot span.
   363      * The number of allocated slots is not stored explicitly, and changes to
   364      * the slots must track changes in the slot span.
   365      */
   366     static bool growSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
   367                           uint32_t newCount);
   368     static void shrinkSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
   369                             uint32_t newCount);
   371     bool hasDynamicSlots() const { return !!slots; }
   373   protected:
   374     static inline bool updateSlotsForSpan(js::ThreadSafeContext *cx,
   375                                           js::HandleObject obj, size_t oldSpan, size_t newSpan);
   377   public:
   378     /*
   379      * Trigger the write barrier on a range of slots that will no longer be
   380      * reachable.
   381      */
   382     void prepareSlotRangeForOverwrite(size_t start, size_t end) {
   383         for (size_t i = start; i < end; i++)
   384             getSlotAddressUnchecked(i)->js::HeapSlot::~HeapSlot();
   385     }
   387     void prepareElementRangeForOverwrite(size_t start, size_t end) {
   388         JS_ASSERT(end <= getDenseInitializedLength());
   389         for (size_t i = start; i < end; i++)
   390             elements[i].js::HeapSlot::~HeapSlot();
   391     }
   393     static bool rollbackProperties(js::ExclusiveContext *cx, js::HandleObject obj,
   394                                    uint32_t slotSpan);
   396     void nativeSetSlot(uint32_t slot, const js::Value &value) {
   397         JS_ASSERT(isNative());
   398         JS_ASSERT(slot < slotSpan());
   399         return setSlot(slot, value);
   400     }
   402     inline bool nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value);
   403     inline void nativeSetSlotWithType(js::ExclusiveContext *cx, js::Shape *shape,
   404                                       const js::Value &value);
   406     inline const js::Value &getReservedSlot(uint32_t index) const {
   407         JS_ASSERT(index < JSSLOT_FREE(getClass()));
   408         return getSlot(index);
   409     }
   411     const js::HeapSlot &getReservedSlotRef(uint32_t index) const {
   412         JS_ASSERT(index < JSSLOT_FREE(getClass()));
   413         return getSlotRef(index);
   414     }
   416     js::HeapSlot &getReservedSlotRef(uint32_t index) {
   417         JS_ASSERT(index < JSSLOT_FREE(getClass()));
   418         return getSlotRef(index);
   419     }
   421     void initReservedSlot(uint32_t index, const js::Value &v) {
   422         JS_ASSERT(index < JSSLOT_FREE(getClass()));
   423         initSlot(index, v);
   424     }
   426     void setReservedSlot(uint32_t index, const js::Value &v) {
   427         JS_ASSERT(index < JSSLOT_FREE(getClass()));
   428         setSlot(index, v);
   429     }
   431     /*
   432      * Marks this object as having a singleton type, and leave the type lazy.
   433      * Constructs a new, unique shape for the object.
   434      */
   435     static inline bool setSingletonType(js::ExclusiveContext *cx, js::HandleObject obj);
   437     // uninlinedGetType() is the same as getType(), but not inlined.
   438     inline js::types::TypeObject* getType(JSContext *cx);
   439     js::types::TypeObject* uninlinedGetType(JSContext *cx);
   441     const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
   442         /* Direct field access for use by GC. */
   443         return type_;
   444     }
   446     /*
   447      * We allow the prototype of an object to be lazily computed if the object
   448      * is a proxy. In the lazy case, we store (JSObject *)0x1 in the proto field
   449      * of the object's TypeObject. We offer three ways of getting the prototype:
   450      *
   451      * 1. obj->getProto() returns the prototype, but asserts if obj is a proxy.
   452      * 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to
   453      *    check if the proto is an object, nullptr, or lazily computed.
   454      * 3. JSObject::getProto(cx, obj, &proto) computes the proto of an object.
   455      *    If obj is a proxy and the proto is lazy, this code may allocate or
   456      *    GC in order to compute the proto. Currently, it will not run JS code.
   457      */
   458     bool uninlinedIsProxy() const;
   459     JSObject *getProto() const {
   460         JS_ASSERT(!uninlinedIsProxy());
   461         return getTaggedProto().toObjectOrNull();
   462     }
   463     static inline bool getProto(JSContext *cx, js::HandleObject obj,
   464                                 js::MutableHandleObject protop);
   465     // Returns false on error, success of operation in outparam.
   466     static inline bool setProto(JSContext *cx, JS::HandleObject obj,
   467                                 JS::HandleObject proto, bool *succeeded);
   469     // uninlinedSetType() is the same as setType(), but not inlined.
   470     inline void setType(js::types::TypeObject *newType);
   471     void uninlinedSetType(js::types::TypeObject *newType);
   473 #ifdef DEBUG
   474     bool hasNewType(const js::Class *clasp, js::types::TypeObject *newType);
   475 #endif
   477     /*
   478      * Mark an object that has been iterated over and is a singleton. We need
   479      * to recover this information in the object's type information after it
   480      * is purged on GC.
   481      */
   482     bool isIteratedSingleton() const {
   483         return lastProperty()->hasObjectFlag(js::BaseShape::ITERATED_SINGLETON);
   484     }
   485     bool setIteratedSingleton(js::ExclusiveContext *cx) {
   486         return setFlag(cx, js::BaseShape::ITERATED_SINGLETON);
   487     }
   489     /*
   490      * Mark an object as requiring its default 'new' type to have unknown
   491      * properties.
   492      */
   493     bool isNewTypeUnknown() const {
   494         return lastProperty()->hasObjectFlag(js::BaseShape::NEW_TYPE_UNKNOWN);
   495     }
   496     static bool setNewTypeUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj);
   498     /* Set a new prototype for an object with a singleton type. */
   499     bool splicePrototype(JSContext *cx, const js::Class *clasp, js::Handle<js::TaggedProto> proto);
   501     /*
   502      * For bootstrapping, whether to splice a prototype for Function.prototype
   503      * or the global object.
   504      */
   505     bool shouldSplicePrototype(JSContext *cx);
   507     /*
   508      * Parents and scope chains.
   509      *
   510      * All script-accessible objects with a nullptr parent are global objects,
   511      * and all global objects have a nullptr parent. Some builtin objects
   512      * which are not script-accessible also have a nullptr parent, such as
   513      * parser created functions for non-compileAndGo scripts.
   514      *
   515      * Except for the non-script-accessible builtins, the global with which an
   516      * object is associated can be reached by following parent links to that
   517      * global (see global()).
   518      *
   519      * The scope chain of an object is the link in the search path when a
   520      * script does a name lookup on a scope object. For JS internal scope
   521      * objects --- Call, DeclEnv and Block --- the chain is stored in
   522      * the first fixed slot of the object, and the object's parent is the
   523      * associated global. For other scope objects, the chain is stored in the
   524      * object's parent.
   525      *
   526      * In compileAndGo code, scope chains can contain only internal scope
   527      * objects with a global object at the root as the scope of the outermost
   528      * non-function script. In non-compileAndGo code, the scope of the
   529      * outermost non-function script might not be a global object, and can have
   530      * a mix of other objects above it before the global object is reached.
   531      */
   533     /* Access the parent link of an object. */
   534     JSObject *getParent() const {
   535         return lastProperty()->getObjectParent();
   536     }
   537     static bool setParent(JSContext *cx, js::HandleObject obj, js::HandleObject newParent);
   539     /*
   540      * Get the enclosing scope of an object. When called on non-scope object,
   541      * this will just be the global (the name "enclosing scope" still applies
   542      * in this situation because non-scope objects can be on the scope chain).
   543      */
   544     inline JSObject *enclosingScope();
   546     /* Access the metadata on an object. */
   547     inline JSObject *getMetadata() const {
   548         return lastProperty()->getObjectMetadata();
   549     }
   550     static bool setMetadata(JSContext *cx, js::HandleObject obj, js::HandleObject newMetadata);
   552     inline js::GlobalObject &global() const;
   553     inline bool isOwnGlobal() const;
   555     /* Remove the type (and prototype) or parent from a new object. */
   556     static inline bool clearType(JSContext *cx, js::HandleObject obj);
   557     static bool clearParent(JSContext *cx, js::HandleObject obj);
   559     /*
   560      * ES5 meta-object properties and operations.
   561      */
   563   private:
   564     enum ImmutabilityType { SEAL, FREEZE };
   566     /*
   567      * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
   568      * object as non-extensible, and adjust each property's attributes appropriately: each
   569      * property becomes non-configurable, and if |freeze|, data properties become
   570      * read-only as well.
   571      */
   572     static bool sealOrFreeze(JSContext *cx, js::HandleObject obj, ImmutabilityType it);
   574     static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp);
   576     static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
   578   public:
   579     /* ES5 15.2.3.8: non-extensible, all props non-configurable */
   580     static inline bool seal(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, SEAL); }
   581     /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
   582     static inline bool freeze(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, FREEZE); }
   584     static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) {
   585         return isSealedOrFrozen(cx, obj, SEAL, resultp);
   586     }
   587     static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) {
   588         return isSealedOrFrozen(cx, obj, FREEZE, resultp);
   589     }
   591     /* toString support. */
   592     static const char *className(JSContext *cx, js::HandleObject obj);
   594     /* Accessors for elements. */
   595     bool ensureElements(js::ThreadSafeContext *cx, uint32_t capacity) {
   596         if (capacity > getDenseCapacity())
   597             return growElements(cx, capacity);
   598         return true;
   599     }
   601     bool growElements(js::ThreadSafeContext *cx, uint32_t newcap);
   602     void shrinkElements(js::ThreadSafeContext *cx, uint32_t cap);
   603     void setDynamicElements(js::ObjectElements *header) {
   604         JS_ASSERT(!hasDynamicElements());
   605         elements = header->elements();
   606         JS_ASSERT(hasDynamicElements());
   607     }
   609     uint32_t getDenseCapacity() {
   610         JS_ASSERT(isNative());
   611         JS_ASSERT(getElementsHeader()->capacity >= getElementsHeader()->initializedLength);
   612         return getElementsHeader()->capacity;
   613     }
   615   private:
   616     inline void ensureDenseInitializedLengthNoPackedCheck(js::ThreadSafeContext *cx,
   617                                                           uint32_t index, uint32_t extra);
   619   public:
   620     void setDenseInitializedLength(uint32_t length) {
   621         JS_ASSERT(isNative());
   622         JS_ASSERT(length <= getDenseCapacity());
   623         prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
   624         getElementsHeader()->initializedLength = length;
   625     }
   627     inline void ensureDenseInitializedLength(js::ExclusiveContext *cx,
   628                                              uint32_t index, uint32_t extra);
   629     inline void ensureDenseInitializedLengthPreservePackedFlag(js::ThreadSafeContext *cx,
   630                                                                uint32_t index, uint32_t extra);
   631     void setDenseElement(uint32_t index, const js::Value &val) {
   632         JS_ASSERT(isNative() && index < getDenseInitializedLength());
   633         elements[index].set(this, js::HeapSlot::Element, index, val);
   634     }
   636     void initDenseElement(uint32_t index, const js::Value &val) {
   637         JS_ASSERT(isNative() && index < getDenseInitializedLength());
   638         elements[index].init(this, js::HeapSlot::Element, index, val);
   639     }
   641     void setDenseElementMaybeConvertDouble(uint32_t index, const js::Value &val) {
   642         if (val.isInt32() && shouldConvertDoubleElements())
   643             setDenseElement(index, js::DoubleValue(val.toInt32()));
   644         else
   645             setDenseElement(index, val);
   646     }
   648     inline bool setDenseElementIfHasType(uint32_t index, const js::Value &val);
   649     inline void setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
   650                                         const js::Value &val);
   651     inline void initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index,
   652                                          const js::Value &val);
   653     inline void setDenseElementHole(js::ExclusiveContext *cx, uint32_t index);
   654     static inline void removeDenseElementForSparseIndex(js::ExclusiveContext *cx,
   655                                                         js::HandleObject obj, uint32_t index);
   657     inline js::Value getDenseOrTypedArrayElement(uint32_t idx);
   659     void copyDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count) {
   660         JS_ASSERT(dstStart + count <= getDenseCapacity());
   661         JSRuntime *rt = runtimeFromMainThread();
   662         if (JS::IsIncrementalBarrierNeeded(rt)) {
   663             JS::Zone *zone = this->zone();
   664             for (uint32_t i = 0; i < count; ++i)
   665                 elements[dstStart + i].set(zone, this, js::HeapSlot::Element, dstStart + i, src[i]);
   666         } else {
   667             memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
   668             DenseRangeWriteBarrierPost(rt, this, dstStart, count);
   669         }
   670     }
   672     void initDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count) {
   673         JS_ASSERT(dstStart + count <= getDenseCapacity());
   674         memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
   675         DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
   676     }
   678     void initDenseElementsUnbarriered(uint32_t dstStart, const js::Value *src, uint32_t count) {
   679         /*
   680          * For use by parallel threads, which since they cannot see nursery
   681          * things do not require a barrier.
   682          */
   683         JS_ASSERT(dstStart + count <= getDenseCapacity());
   684 #if defined(DEBUG) && defined(JSGC_GENERATIONAL)
   685         JS::shadow::Runtime *rt = JS::shadow::Runtime::asShadowRuntime(runtimeFromAnyThread());
   686         JS_ASSERT(!js::gc::IsInsideNursery(rt, this));
   687         for (uint32_t index = 0; index < count; ++index) {
   688             const JS::Value& value = src[index];
   689             if (value.isMarkable())
   690                 JS_ASSERT(!js::gc::IsInsideNursery(rt, value.toGCThing()));
   691         }
   692 #endif
   693         memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
   694     }
   696     void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
   697         JS_ASSERT(dstStart + count <= getDenseCapacity());
   698         JS_ASSERT(srcStart + count <= getDenseInitializedLength());
   700         /*
   701          * Using memmove here would skip write barriers. Also, we need to consider
   702          * an array containing [A, B, C], in the following situation:
   703          *
   704          * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
   705          * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
   706          * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
   707          *
   708          * Since normal marking never happens on B, it is very important that the
   709          * write barrier is invoked here on B, despite the fact that it exists in
   710          * the array before and after the move.
   711         */
   712         JS::Zone *zone = this->zone();
   713         JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
   714         if (shadowZone->needsBarrier()) {
   715             if (dstStart < srcStart) {
   716                 js::HeapSlot *dst = elements + dstStart;
   717                 js::HeapSlot *src = elements + srcStart;
   718                 for (uint32_t i = 0; i < count; i++, dst++, src++)
   719                     dst->set(zone, this, js::HeapSlot::Element, dst - elements, *src);
   720             } else {
   721                 js::HeapSlot *dst = elements + dstStart + count - 1;
   722                 js::HeapSlot *src = elements + srcStart + count - 1;
   723                 for (uint32_t i = 0; i < count; i++, dst--, src--)
   724                     dst->set(zone, this, js::HeapSlot::Element, dst - elements, *src);
   725             }
   726         } else {
   727             memmove(elements + dstStart, elements + srcStart, count * sizeof(js::HeapSlot));
   728             DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
   729         }
   730     }
   732     void moveDenseElementsNoPreBarrier(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
   733         JS_ASSERT(!shadowZone()->needsBarrier());
   735         JS_ASSERT(dstStart + count <= getDenseCapacity());
   736         JS_ASSERT(srcStart + count <= getDenseCapacity());
   738         memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
   739         DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
   740     }
   742     bool shouldConvertDoubleElements() {
   743         JS_ASSERT(getClass()->isNative());
   744         return getElementsHeader()->shouldConvertDoubleElements();
   745     }
   747     inline void setShouldConvertDoubleElements();
   748     inline void clearShouldConvertDoubleElements();
   750     /* Packed information for this object's elements. */
   751     inline bool writeToIndexWouldMarkNotPacked(uint32_t index);
   752     inline void markDenseElementsNotPacked(js::ExclusiveContext *cx);
   754     /*
   755      * ensureDenseElements ensures that the object can hold at least
   756      * index + extra elements. It returns ED_OK on success, ED_FAILED on
   757      * failure to grow the array, ED_SPARSE when the object is too sparse to
   758      * grow (this includes the case of index + extra overflow). In the last
   759      * two cases the object is kept intact.
   760      */
   761     enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
   763   private:
   764     inline EnsureDenseResult ensureDenseElementsNoPackedCheck(js::ThreadSafeContext *cx,
   765                                                               uint32_t index, uint32_t extra);
   767   public:
   768     inline EnsureDenseResult ensureDenseElements(js::ExclusiveContext *cx,
   769                                                  uint32_t index, uint32_t extra);
   770     inline EnsureDenseResult ensureDenseElementsPreservePackedFlag(js::ThreadSafeContext *cx,
   771                                                                    uint32_t index, uint32_t extra);
   773     inline EnsureDenseResult extendDenseElements(js::ThreadSafeContext *cx,
   774                                                  uint32_t requiredCapacity, uint32_t extra);
   776     /* Convert a single dense element to a sparse property. */
   777     static bool sparsifyDenseElement(js::ExclusiveContext *cx,
   778                                      js::HandleObject obj, uint32_t index);
   780     /* Convert all dense elements to sparse properties. */
   781     static bool sparsifyDenseElements(js::ExclusiveContext *cx, js::HandleObject obj);
   783     /* Small objects are dense, no matter what. */
   784     static const uint32_t MIN_SPARSE_INDEX = 1000;
   786     /*
   787      * Element storage for an object will be sparse if fewer than 1/8 indexes
   788      * are filled in.
   789      */
   790     static const unsigned SPARSE_DENSITY_RATIO = 8;
   792     /*
   793      * Check if after growing the object's elements will be too sparse.
   794      * newElementsHint is an estimated number of elements to be added.
   795      */
   796     bool willBeSparseElements(uint32_t requiredCapacity, uint32_t newElementsHint);
   798     /*
   799      * After adding a sparse index to obj, see if it should be converted to use
   800      * dense elements.
   801      */
   802     static EnsureDenseResult maybeDensifySparseElements(js::ExclusiveContext *cx, js::HandleObject obj);
   804   public:
   805     /*
   806      * Iterator-specific getters and setters.
   807      */
   809     static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
   811     /*
   812      * Back to generic stuff.
   813      */
   814     bool isCallable() {
   815         return getClass()->isCallable();
   816     }
   818     inline void finish(js::FreeOp *fop);
   819     MOZ_ALWAYS_INLINE void finalize(js::FreeOp *fop);
   821     static inline bool hasProperty(JSContext *cx, js::HandleObject obj,
   822                                    js::HandleId id, bool *foundp);
   824     /*
   825      * Allocate and free an object slot.
   826      *
   827      * FIXME: bug 593129 -- slot allocation should be done by object methods
   828      * after calling object-parameter-free shape methods, avoiding coupling
   829      * logic across the object vs. shape module wall.
   830      */
   831     static bool allocSlot(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t *slotp);
   832     void freeSlot(uint32_t slot);
   834   public:
   835     static bool reportReadOnly(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
   836     bool reportNotConfigurable(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
   837     bool reportNotExtensible(js::ThreadSafeContext *cx, unsigned report = JSREPORT_ERROR);
   839     /*
   840      * Get the property with the given id, then call it as a function with the
   841      * given arguments, providing this object as |this|. If the property isn't
   842      * callable a TypeError will be thrown. On success the value returned by
   843      * the call is stored in *vp.
   844      */
   845     bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv,
   846                     js::MutableHandleValue vp);
   848   private:
   849     static js::Shape *getChildPropertyOnDictionary(js::ThreadSafeContext *cx, JS::HandleObject obj,
   850                                                    js::HandleShape parent, js::StackShape &child);
   851     static js::Shape *getChildProperty(js::ExclusiveContext *cx, JS::HandleObject obj,
   852                                        js::HandleShape parent, js::StackShape &child);
   853     template <js::ExecutionMode mode>
   854     static inline js::Shape *
   855     getOrLookupChildProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
   856                              JS::HandleObject obj, js::HandleShape parent, js::StackShape &child)
   857     {
   858         if (mode == js::ParallelExecution)
   859             return lookupChildProperty(cx, obj, parent, child);
   860         return getChildProperty(cx->asExclusiveContext(), obj, parent, child);
   861     }
   863   public:
   864     /*
   865      * XXX: This should be private, but is public because it needs to be a
   866      * friend of ThreadSafeContext to get to the propertyTree on cx->compartment_.
   867      */
   868     static js::Shape *lookupChildProperty(js::ThreadSafeContext *cx, JS::HandleObject obj,
   869                                           js::HandleShape parent, js::StackShape &child);
   872   protected:
   873     /*
   874      * Internal helper that adds a shape not yet mapped by this object.
   875      *
   876      * Notes:
   877      * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
   878      * 2. Checks for non-extensibility must be done by callers.
   879      */
   880     template <js::ExecutionMode mode>
   881     static js::Shape *
   882     addPropertyInternal(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
   883                         JS::HandleObject obj, JS::HandleId id,
   884                         JSPropertyOp getter, JSStrictPropertyOp setter,
   885                         uint32_t slot, unsigned attrs, unsigned flags, js::Shape **spp,
   886                         bool allowDictionary);
   888   private:
   889     struct TradeGutsReserved;
   890     static bool ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
   891                                     TradeGutsReserved &reserved);
   893     static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b,
   894                           TradeGutsReserved &reserved);
   896   public:
   897     /* Add a property whose id is not yet in this scope. */
   898     static js::Shape *addProperty(js::ExclusiveContext *cx, JS::HandleObject, JS::HandleId id,
   899                                   JSPropertyOp getter, JSStrictPropertyOp setter,
   900                                   uint32_t slot, unsigned attrs, unsigned flags,
   901                                   bool allowDictionary = true);
   903     /* Add a data property whose id is not yet in this scope. */
   904     js::Shape *addDataProperty(js::ExclusiveContext *cx,
   905                                jsid id_, uint32_t slot, unsigned attrs);
   906     js::Shape *addDataProperty(js::ExclusiveContext *cx, js::HandlePropertyName name,
   907                                uint32_t slot, unsigned attrs);
   909     /* Add or overwrite a property for id in this scope. */
   910     template <js::ExecutionMode mode>
   911     static js::Shape *
   912     putProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
   913                 JS::HandleObject obj, JS::HandleId id,
   914                 JSPropertyOp getter, JSStrictPropertyOp setter,
   915                 uint32_t slot, unsigned attrs,
   916                 unsigned flags);
   917     template <js::ExecutionMode mode>
   918     static inline js::Shape *
   919     putProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
   920                 JS::HandleObject obj, js::PropertyName *name,
   921                 JSPropertyOp getter, JSStrictPropertyOp setter,
   922                 uint32_t slot, unsigned attrs,
   923                 unsigned flags);
   925     /* Change the given property into a sibling with the same id in this scope. */
   926     template <js::ExecutionMode mode>
   927     static js::Shape *
   928     changeProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
   929                    js::HandleObject obj, js::HandleShape shape, unsigned attrs, unsigned mask,
   930                    JSPropertyOp getter, JSStrictPropertyOp setter);
   932     static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
   933                                                 js::HandleShape shape, unsigned attrs);
   935     /* Remove the property named by id from this object. */
   936     bool removeProperty(js::ExclusiveContext *cx, jsid id);
   938     /* Clear the scope, making it empty. */
   939     static void clear(JSContext *cx, js::HandleObject obj);
   941     static bool lookupGeneric(JSContext *cx, js::HandleObject obj, js::HandleId id,
   942                               js::MutableHandleObject objp, js::MutableHandleShape propp);
   944     static bool lookupProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name,
   945                                js::MutableHandleObject objp, js::MutableHandleShape propp)
   946     {
   947         JS::RootedId id(cx, js::NameToId(name));
   948         return lookupGeneric(cx, obj, id, objp, propp);
   949     }
   951     static bool lookupElement(JSContext *cx, js::HandleObject obj, uint32_t index,
   952                               js::MutableHandleObject objp, js::MutableHandleShape propp)
   953     {
   954         js::LookupElementOp op = obj->getOps()->lookupElement;
   955         return (op ? op : js::baseops::LookupElement)(cx, obj, index, objp, propp);
   956     }
   958     static bool defineGeneric(js::ExclusiveContext *cx, js::HandleObject obj,
   959                               js::HandleId id, js::HandleValue value,
   960                               JSPropertyOp getter = JS_PropertyStub,
   961                               JSStrictPropertyOp setter = JS_StrictPropertyStub,
   962                               unsigned attrs = JSPROP_ENUMERATE);
   964     static bool defineProperty(js::ExclusiveContext *cx, js::HandleObject obj,
   965                                js::PropertyName *name, js::HandleValue value,
   966                                JSPropertyOp getter = JS_PropertyStub,
   967                                JSStrictPropertyOp setter = JS_StrictPropertyStub,
   968                                unsigned attrs = JSPROP_ENUMERATE);
   970     static bool defineElement(js::ExclusiveContext *cx, js::HandleObject obj,
   971                               uint32_t index, js::HandleValue value,
   972                               JSPropertyOp getter = JS_PropertyStub,
   973                               JSStrictPropertyOp setter = JS_StrictPropertyStub,
   974                               unsigned attrs = JSPROP_ENUMERATE);
   976     static bool getGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
   977                            js::HandleId id, js::MutableHandleValue vp)
   978     {
   979         JS_ASSERT(!!obj->getOps()->getGeneric == !!obj->getOps()->getProperty);
   980         js::GenericIdOp op = obj->getOps()->getGeneric;
   981         if (op) {
   982             if (!op(cx, obj, receiver, id, vp))
   983                 return false;
   984         } else {
   985             if (!js::baseops::GetProperty(cx, obj, receiver, id, vp))
   986                 return false;
   987         }
   988         return true;
   989     }
   991     static bool getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
   992                                jsid id, js::Value *vp)
   993     {
   994         js::GenericIdOp op = obj->getOps()->getGeneric;
   995         if (op)
   996             return false;
   997         return js::baseops::GetPropertyNoGC(cx, obj, receiver, id, vp);
   998     }
  1000     static bool getProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
  1001                             js::PropertyName *name, js::MutableHandleValue vp)
  1003         JS::RootedId id(cx, js::NameToId(name));
  1004         return getGeneric(cx, obj, receiver, id, vp);
  1007     static bool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
  1008                                 js::PropertyName *name, js::Value *vp)
  1010         return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp);
  1013     static inline bool getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
  1014                                   uint32_t index, js::MutableHandleValue vp);
  1015     static inline bool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
  1016                                       uint32_t index, js::Value *vp);
  1018     static bool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
  1019                            js::HandleId id, js::MutableHandleValue vp, bool strict)
  1021         if (obj->getOps()->setGeneric)
  1022             return nonNativeSetProperty(cx, obj, id, vp, strict);
  1023         return js::baseops::SetPropertyHelper<js::SequentialExecution>(
  1024             cx, obj, receiver, id, js::baseops::Qualified, vp, strict);
  1027     static bool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
  1028                             js::PropertyName *name,
  1029                             js::MutableHandleValue vp, bool strict)
  1031         JS::RootedId id(cx, js::NameToId(name));
  1032         return setGeneric(cx, obj, receiver, id, vp, strict);
  1035     static bool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
  1036                            uint32_t index, js::MutableHandleValue vp, bool strict)
  1038         if (obj->getOps()->setElement)
  1039             return nonNativeSetElement(cx, obj, index, vp, strict);
  1040         return js::baseops::SetElementHelper(cx, obj, receiver, index, vp, strict);
  1043     static bool nonNativeSetProperty(JSContext *cx, js::HandleObject obj,
  1044                                      js::HandleId id, js::MutableHandleValue vp, bool strict);
  1045     static bool nonNativeSetElement(JSContext *cx, js::HandleObject obj,
  1046                                     uint32_t index, js::MutableHandleValue vp, bool strict);
  1048     static bool getGenericAttributes(JSContext *cx, js::HandleObject obj,
  1049                                      js::HandleId id, unsigned *attrsp)
  1051         js::GenericAttributesOp op = obj->getOps()->getGenericAttributes;
  1052         return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
  1055     static inline bool setGenericAttributes(JSContext *cx, js::HandleObject obj,
  1056                                             js::HandleId id, unsigned *attrsp);
  1058     static inline bool deleteProperty(JSContext *cx, js::HandleObject obj,
  1059                                       js::HandlePropertyName name,
  1060                                       bool *succeeded);
  1061     static inline bool deleteElement(JSContext *cx, js::HandleObject obj,
  1062                                      uint32_t index, bool *succeeded);
  1063     static bool deleteByValue(JSContext *cx, js::HandleObject obj,
  1064                               const js::Value &property, bool *succeeded);
  1066     static inline bool watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
  1067                              JS::HandleObject callable);
  1068     static inline bool unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
  1070     static bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop,
  1071                           JS::MutableHandleValue statep, JS::MutableHandleId idp)
  1073         JSNewEnumerateOp op = obj->getOps()->enumerate;
  1074         return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
  1077     static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint,
  1078                              js::MutableHandleValue vp)
  1080         JSConvertOp op = obj->getClass()->convert;
  1081         bool ok;
  1082         if (op == JS_ConvertStub)
  1083             ok = js::DefaultValue(cx, obj, hint, vp);
  1084         else
  1085             ok = op(cx, obj, hint, vp);
  1086         JS_ASSERT_IF(ok, vp.isPrimitive());
  1087         return ok;
  1090     static JSObject *thisObject(JSContext *cx, js::HandleObject obj)
  1092         JSObjectOp op = obj->getOps()->thisObject;
  1093         return op ? op(cx, obj) : obj;
  1096     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
  1098     static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b);
  1100     inline void initArrayClass();
  1102     /*
  1103      * In addition to the generic object interface provided by JSObject,
  1104      * specific types of objects may provide additional operations. To access,
  1105      * these addition operations, callers should use the pattern:
  1107      *   if (obj.is<XObject>()) {
  1108      *     XObject &x = obj.as<XObject>();
  1109      *     x.foo();
  1110      *   }
  1112      * These XObject classes form a hierarchy. For example, for a cloned block
  1113      * object, the following predicates are true: is<ClonedBlockObject>,
  1114      * is<BlockObject>, is<NestedScopeObject> and is<ScopeObject>. Each of
  1115      * these has a respective class that derives and adds operations.
  1117      * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
  1118      * triplet (along with any class YObject that derives XObject).
  1120      * Note that X represents a low-level representation and does not query the
  1121      * [[Class]] property of object defined by the spec (for this, see
  1122      * js::ObjectClassIs).
  1123      */
  1125     template <class T>
  1126     inline bool is() const { return getClass() == &T::class_; }
  1128     template <class T>
  1129     T &as() {
  1130         JS_ASSERT(is<T>());
  1131         return *static_cast<T *>(this);
  1134     template <class T>
  1135     const T &as() const {
  1136         JS_ASSERT(is<T>());
  1137         return *static_cast<const T *>(this);
  1140     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; }
  1142 #ifdef DEBUG
  1143     void dump();
  1144 #endif
  1146   private:
  1147     static void staticAsserts() {
  1148         static_assert(sizeof(JSObject) == sizeof(js::shadow::Object),
  1149                       "shadow interface must match actual interface");
  1150         static_assert(sizeof(JSObject) == sizeof(js::ObjectImpl),
  1151                       "JSObject itself must not have any fields");
  1152         static_assert(sizeof(JSObject) % sizeof(js::Value) == 0,
  1153                       "fixed slots after an object must be aligned");
  1154         static_assert(js::shadow::Object::MAX_FIXED_SLOTS == MAX_FIXED_SLOTS,
  1155                       "We shouldn't be confused about our actual maximum "
  1156                       "number of fixed slots");
  1159     JSObject() MOZ_DELETE;
  1160     JSObject(const JSObject &other) MOZ_DELETE;
  1161     void operator=(const JSObject &other) MOZ_DELETE;
  1162 };
  1164 template <class U>
  1165 MOZ_ALWAYS_INLINE JS::Handle<U*>
  1166 js::RootedBase<JSObject*>::as() const
  1168     const JS::Rooted<JSObject*> &self = *static_cast<const JS::Rooted<JSObject*>*>(this);
  1169     JS_ASSERT(self->is<U>());
  1170     return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
  1173 /*
  1174  * The only sensible way to compare JSObject with == is by identity. We use
  1175  * const& instead of * as a syntactic way to assert non-null. This leads to an
  1176  * abundance of address-of operators to identity. Hence this overload.
  1177  */
  1178 static MOZ_ALWAYS_INLINE bool
  1179 operator==(const JSObject &lhs, const JSObject &rhs)
  1181     return &lhs == &rhs;
  1184 static MOZ_ALWAYS_INLINE bool
  1185 operator!=(const JSObject &lhs, const JSObject &rhs)
  1187     return &lhs != &rhs;
  1190 struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
  1191 struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
  1192 struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };
  1193 struct JSObject_Slots12 : JSObject { js::Value fslots[12]; };
  1194 struct JSObject_Slots16 : JSObject { js::Value fslots[16]; };
  1196 static inline bool
  1197 js_IsCallable(const js::Value &v)
  1199     return v.isObject() && v.toObject().isCallable();
  1202 inline JSObject *
  1203 GetInnerObject(JSContext *cx, js::HandleObject obj)
  1205     if (JSObjectOp op = obj->getClass()->ext.innerObject)
  1206         return op(cx, obj);
  1207     return obj;
  1210 inline JSObject *
  1211 GetOuterObject(JSContext *cx, js::HandleObject obj)
  1213     if (JSObjectOp op = obj->getClass()->ext.outerObject)
  1214         return op(cx, obj);
  1215     return obj;
  1218 class JSValueArray {
  1219   public:
  1220     const jsval *array;
  1221     size_t length;
  1223     JSValueArray(const jsval *v, size_t c) : array(v), length(c) {}
  1224 };
  1226 class ValueArray {
  1227   public:
  1228     js::Value *array;
  1229     size_t length;
  1231     ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
  1232 };
  1234 namespace js {
  1236 /* Set *resultp to tell whether obj has an own property with the given id. */
  1237 bool
  1238 HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *resultp);
  1240 template <AllowGC allowGC>
  1241 extern bool
  1242 HasOwnProperty(JSContext *cx, LookupGenericOp lookup,
  1243                typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
  1244                typename MaybeRooted<jsid, allowGC>::HandleType id,
  1245                typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
  1246                typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
  1248 typedef JSObject *(*ClassInitializerOp)(JSContext *cx, JS::HandleObject obj);
  1250 /* Fast access to builtin constructors and prototypes. */
  1251 bool
  1252 GetBuiltinConstructor(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp);
  1254 bool
  1255 GetBuiltinPrototype(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp);
  1257 const Class *
  1258 ProtoKeyToClass(JSProtoKey key);
  1260 JSObject *
  1261 GetBuiltinPrototypePure(GlobalObject *global, JSProtoKey protoKey);
  1263 extern bool
  1264 SetClassAndProto(JSContext *cx, HandleObject obj,
  1265                  const Class *clasp, Handle<TaggedProto> proto, bool *succeeded);
  1267 /*
  1268  * Property-lookup-based access to interface and prototype objects for classes.
  1269  * If the class is built-in (hhas a non-null JSProtoKey), these forward to
  1270  * GetClass{Object,Prototype}.
  1271  */
  1273 bool
  1274 FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp);
  1276 extern bool
  1277 FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp);
  1279 } /* namespace js */
  1281 /*
  1282  * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
  1283  */
  1284 extern const char js_watch_str[];
  1285 extern const char js_unwatch_str[];
  1286 extern const char js_hasOwnProperty_str[];
  1287 extern const char js_isPrototypeOf_str[];
  1288 extern const char js_propertyIsEnumerable_str[];
  1290 #ifdef JS_OLD_GETTER_SETTER_METHODS
  1291 extern const char js_defineGetter_str[];
  1292 extern const char js_defineSetter_str[];
  1293 extern const char js_lookupGetter_str[];
  1294 extern const char js_lookupSetter_str[];
  1295 #endif
  1297 extern bool
  1298 js_PopulateObject(JSContext *cx, js::HandleObject newborn, js::HandleObject props);
  1301 namespace js {
  1303 extern bool
  1304 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
  1305                   JS::HandleValue descriptor, bool *bp);
  1307 extern bool
  1308 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
  1309                   JS::Handle<js::PropertyDescriptor> descriptor, bool *bp);
  1311 /*
  1312  * The NewObjectKind allows an allocation site to specify the type properties
  1313  * and lifetime requirements that must be fixed at allocation time.
  1314  */
  1315 enum NewObjectKind {
  1316     /* This is the default. Most objects are generic. */
  1317     GenericObject,
  1319     /*
  1320      * Singleton objects are treated specially by the type system. This flag
  1321      * ensures that the new object is automatically set up correctly as a
  1322      * singleton and is allocated in the correct heap.
  1323      */
  1324     SingletonObject,
  1326     /*
  1327      * Objects which may be marked as a singleton after allocation must still
  1328      * be allocated on the correct heap, but are not automatically setup as a
  1329      * singleton after allocation.
  1330      */
  1331     MaybeSingletonObject,
  1333     /*
  1334      * Objects which will not benefit from being allocated in the nursery
  1335      * (e.g. because they are known to have a long lifetime) may be allocated
  1336      * with this kind to place them immediately into the tenured generation.
  1337      */
  1338     TenuredObject
  1339 };
  1341 inline gc::InitialHeap
  1342 GetInitialHeap(NewObjectKind newKind, const Class *clasp)
  1344     if (clasp->finalize || newKind != GenericObject)
  1345         return gc::TenuredHeap;
  1346     return gc::DefaultHeap;
  1349 // Specialized call for constructing |this| with a known function callee,
  1350 // and a known prototype.
  1351 extern JSObject *
  1352 CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto,
  1353                                NewObjectKind newKind = GenericObject);
  1355 // Specialized call for constructing |this| with a known function callee.
  1356 extern JSObject *
  1357 CreateThisForFunction(JSContext *cx, js::HandleObject callee, NewObjectKind newKind);
  1359 // Generic call for constructing |this|.
  1360 extern JSObject *
  1361 CreateThis(JSContext *cx, const js::Class *clasp, js::HandleObject callee);
  1363 extern JSObject *
  1364 CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent);
  1366 extern JSObject *
  1367 DeepCloneObjectLiteral(JSContext *cx, HandleObject obj, NewObjectKind newKind = GenericObject);
  1369 /*
  1370  * Return successfully added or changed shape or nullptr on error.
  1371  */
  1372 extern bool
  1373 DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
  1374                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
  1376 extern bool
  1377 LookupNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id,
  1378                      js::MutableHandleObject objp, js::MutableHandleShape propp);
  1380 /*
  1381  * Call the [[DefineOwnProperty]] internal method of obj.
  1383  * If obj is an array, this follows ES5 15.4.5.1.
  1384  * If obj is any other native object, this follows ES5 8.12.9.
  1385  * If obj is a proxy, this calls the proxy handler's defineProperty method.
  1386  * Otherwise, this reports an error and returns false.
  1387  */
  1388 extern bool
  1389 DefineProperty(JSContext *cx, js::HandleObject obj,
  1390                js::HandleId id, const PropDesc &desc, bool throwError,
  1391                bool *rval);
  1393 bool
  1394 DefineProperties(JSContext *cx, HandleObject obj, HandleObject props);
  1396 /*
  1397  * Read property descriptors from props, as for Object.defineProperties. See
  1398  * ES5 15.2.3.7 steps 3-5.
  1399  */
  1400 extern bool
  1401 ReadPropertyDescriptors(JSContext *cx, HandleObject props, bool checkAccessors,
  1402                         AutoIdVector *ids, AutoPropDescArrayRooter *descs);
  1404 /* Read the name using a dynamic lookup on the scopeChain. */
  1405 extern bool
  1406 LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
  1407            MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
  1409 extern bool
  1410 LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain,
  1411                JSObject **objp, JSObject **pobjp, Shape **propp);
  1413 /*
  1414  * Like LookupName except returns the global object if 'name' is not found in
  1415  * any preceding non-global scope.
  1417  * Additionally, pobjp and propp are not needed by callers so they are not
  1418  * returned.
  1419  */
  1420 extern bool
  1421 LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
  1422                             MutableHandleObject objp);
  1426 extern JSObject *
  1427 js_FindVariableScope(JSContext *cx, JSFunction **funp);
  1430 namespace js {
  1432 bool
  1433 NativeGet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> pobj,
  1434           js::Handle<js::Shape*> shape, js::MutableHandle<js::Value> vp);
  1436 template <js::ExecutionMode mode>
  1437 bool
  1438 NativeSet(typename js::ExecutionModeTraits<mode>::ContextType cx,
  1439           js::Handle<JSObject*> obj, js::Handle<JSObject*> receiver,
  1440           js::Handle<js::Shape*> shape, bool strict, js::MutableHandleValue vp);
  1442 bool
  1443 LookupPropertyPure(JSObject *obj, jsid id, JSObject **objp, Shape **propp);
  1445 bool
  1446 GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, Value *vp);
  1448 inline bool
  1449 GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, PropertyName *name, Value *vp)
  1451     return GetPropertyPure(cx, obj, NameToId(name), vp);
  1454 bool
  1455 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
  1456                          MutableHandle<PropertyDescriptor> desc);
  1458 bool
  1459 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
  1461 bool
  1462 NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
  1464 /*
  1465  * If obj has an already-resolved data property for id, return true and
  1466  * store the property value in *vp.
  1467  */
  1468 extern bool
  1469 HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
  1471 inline bool
  1472 HasDataProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp)
  1474     return HasDataProperty(cx, obj, NameToId(name), vp);
  1477 extern bool
  1478 IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result);
  1480 // obj is a JSObject*, but we root it immediately up front. We do it
  1481 // that way because we need a Rooted temporary in this method anyway.
  1482 extern bool
  1483 IsDelegateOfObject(JSContext *cx, HandleObject protoObj, JSObject* obj, bool *result);
  1485 bool
  1486 GetObjectElementOperationPure(ThreadSafeContext *cx, JSObject *obj, const Value &prop, Value *vp);
  1488 /* Wrap boolean, number or string as Boolean, Number or String object. */
  1489 extern JSObject *
  1490 PrimitiveToObject(JSContext *cx, const Value &v);
  1492 } /* namespace js */
  1494 namespace js {
  1496 /*
  1497  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
  1498  * already be an object, use ToObject. reportCantConvert controls how null and
  1499  * undefined errors are reported.
  1500  */
  1501 extern JSObject *
  1502 ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack);
  1504 /* For object conversion in e.g. native functions. */
  1505 MOZ_ALWAYS_INLINE JSObject *
  1506 ToObject(JSContext *cx, HandleValue vp)
  1508     if (vp.isObject())
  1509         return &vp.toObject();
  1510     return ToObjectSlow(cx, vp, false);
  1513 /* For converting stack values to objects. */
  1514 MOZ_ALWAYS_INLINE JSObject *
  1515 ToObjectFromStack(JSContext *cx, HandleValue vp)
  1517     if (vp.isObject())
  1518         return &vp.toObject();
  1519     return ToObjectSlow(cx, vp, true);
  1522 template<XDRMode mode>
  1523 bool
  1524 XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleObject obj);
  1526 extern JSObject *
  1527 CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj);
  1529 } /* namespace js */
  1531 extern void
  1532 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
  1534 extern bool
  1535 js_ReportGetterOnlyAssignment(JSContext *cx, bool strict);
  1538 namespace js {
  1540 extern JSObject *
  1541 NonNullObject(JSContext *cx, const Value &v);
  1543 extern const char *
  1544 InformalValueTypeName(const Value &v);
  1546 extern bool
  1547 GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method,
  1548                          MutableHandleObject objp);
  1550 /* Helpers for throwing. These always return false. */
  1551 extern bool
  1552 Throw(JSContext *cx, jsid id, unsigned errorNumber);
  1554 extern bool
  1555 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
  1557 }  /* namespace js */
  1559 #endif /* jsobj_h */

mercurial