| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jsobj_h |
| #define jsobj_h |
| |
| /* |
| * JS object definitions. |
| * |
| * A JS object consists of a possibly-shared object descriptor containing |
| * ordered property names, called the map; and a dense vector of property |
| * values, called slots. The map/slot pointer pair is GC'ed, while the map |
| * is reference counted and the slot vector is malloc'ed. |
| */ |
| #include "jsapi.h" |
| #include "jsatom.h" |
| #include "jsclass.h" |
| #include "jsfriendapi.h" |
| |
| #include "gc/Barrier.h" |
| #include "gc/Heap.h" |
| |
| #include "vm/ObjectImpl.h" |
| #include "vm/String.h" |
| |
| namespace JS { |
| struct ObjectsExtraSizes; |
| } |
| |
| namespace js { |
| |
| class AutoPropDescArrayRooter; |
| class BaseProxyHandler; |
| struct GCMarker; |
| struct NativeIterator; |
| class Nursery; |
| class Shape; |
| struct StackShape; |
| |
| namespace mjit { class Compiler; } |
| |
| inline JSObject * |
| CastAsObject(PropertyOp op) |
| { |
| return JS_FUNC_TO_DATA_PTR(JSObject *, op); |
| } |
| |
| inline JSObject * |
| CastAsObject(StrictPropertyOp op) |
| { |
| return JS_FUNC_TO_DATA_PTR(JSObject *, op); |
| } |
| |
| inline Value |
| CastAsObjectJsval(PropertyOp op) |
| { |
| return ObjectOrNullValue(CastAsObject(op)); |
| } |
| |
| inline Value |
| CastAsObjectJsval(StrictPropertyOp op) |
| { |
| return ObjectOrNullValue(CastAsObject(op)); |
| } |
| |
| /******************************************************************************/ |
| |
| typedef Vector<PropDesc, 1> PropDescArray; |
| |
| /* |
| * The baseops namespace encapsulates the default behavior when performing |
| * various operations on an object, irrespective of hooks installed in the |
| * object's class. In general, instance methods on the object itself should be |
| * called instead of calling these methods directly. |
| */ |
| namespace baseops { |
| |
| /* |
| * On success, and if id was found, return true with *objp non-null and with a |
| * property of *objp stored in *propp. If successful but id was not found, |
| * return true with both *objp and *propp null. |
| */ |
| template <AllowGC allowGC> |
| extern JSBool |
| LookupProperty(JSContext *cx, |
| typename MaybeRooted<JSObject*, allowGC>::HandleType obj, |
| typename MaybeRooted<jsid, allowGC>::HandleType id, |
| typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp, |
| typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp); |
| |
| inline bool |
| LookupProperty(JSContext *cx, HandleObject obj, PropertyName *name, |
| MutableHandleObject objp, MutableHandleShape propp) |
| { |
| Rooted<jsid> id(cx, NameToId(name)); |
| return LookupProperty<CanGC>(cx, obj, id, objp, propp); |
| } |
| |
| extern JSBool |
| LookupElement(JSContext *cx, HandleObject obj, uint32_t index, |
| MutableHandleObject objp, MutableHandleShape propp); |
| |
| extern JSBool |
| DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, |
| JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); |
| |
| inline JSBool |
| DefineProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue value, |
| JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) |
| { |
| Rooted<jsid> id(cx, NameToId(name)); |
| return DefineGeneric(cx, obj, id, value, getter, setter, attrs); |
| } |
| |
| extern JSBool |
| DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value, |
| JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); |
| |
| extern JSBool |
| GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, MutableHandleValue vp); |
| |
| extern JSBool |
| GetPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp); |
| |
| extern JSBool |
| GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp); |
| |
| inline JSBool |
| GetProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
| { |
| return GetProperty(cx, obj, obj, id, vp); |
| } |
| |
| inline JSBool |
| GetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp) |
| { |
| return GetElement(cx, obj, obj, index, vp); |
| } |
| |
| extern JSBool |
| GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, HandleValue def, MutableHandleValue vp); |
| |
| extern JSBool |
| SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, |
| unsigned defineHow, MutableHandleValue vp, JSBool strict); |
| |
| inline bool |
| SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name, |
| unsigned defineHow, MutableHandleValue vp, JSBool strict) |
| { |
| Rooted<jsid> id(cx, NameToId(name)); |
| return SetPropertyHelper(cx, obj, receiver, id, defineHow, vp, strict); |
| } |
| |
| extern JSBool |
| SetElementHelper(JSContext *cx, HandleObject obj, HandleObject Receiver, uint32_t index, |
| unsigned defineHow, MutableHandleValue vp, JSBool strict); |
| |
| extern JSType |
| TypeOf(JSContext *cx, HandleObject obj); |
| |
| extern JSBool |
| GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp); |
| |
| extern JSBool |
| SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp); |
| |
| extern JSBool |
| GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp); |
| |
| extern JSBool |
| SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp); |
| |
| extern JSBool |
| DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded); |
| |
| extern JSBool |
| DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded); |
| |
| extern JSBool |
| DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded); |
| |
| extern JSBool |
| DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded); |
| |
| } /* namespace js::baseops */ |
| |
| extern Class ArrayClass; |
| extern Class DateClass; |
| extern Class ErrorClass; |
| extern Class IntlClass; |
| extern Class JSONClass; |
| extern Class MathClass; |
| extern Class ObjectClass; |
| extern Class ProxyClass; |
| extern Class RegExpStaticsClass; |
| |
| class ArrayBufferObject; |
| class GlobalObject; |
| class MapObject; |
| class NewObjectCache; |
| class NormalArgumentsObject; |
| class SetObject; |
| class StrictArgumentsObject; |
| |
| } /* namespace js */ |
| |
| #define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp) |
| |
| /* |
| * The public interface for an object. |
| * |
| * Implementation of the underlying structure occurs in ObjectImpl, from which |
| * this struct inherits. This inheritance is currently public, but it will |
| * eventually be made protected. For full details, see vm/ObjectImpl.{h,cpp}. |
| * |
| * The JSFunction struct is an extension of this struct allocated from a larger |
| * GC size-class. |
| */ |
| class JSObject : public js::ObjectImpl |
| { |
| private: |
| friend class js::Shape; |
| friend struct js::GCMarker; |
| friend class js::NewObjectCache; |
| friend class js::Nursery; |
| |
| /* Make the type object to use for LAZY_TYPE objects. */ |
| static js::types::TypeObject *makeLazyType(JSContext *cx, js::HandleObject obj); |
| |
| public: |
| /* |
| * Update the last property, keeping the number of allocated slots in sync |
| * with the object's new slot span. |
| */ |
| static bool setLastProperty(JSContext *cx, JS::HandleObject obj, js::HandleShape shape); |
| |
| /* As above, but does not change the slot span. */ |
| inline void setLastPropertyInfallible(js::Shape *shape); |
| |
| /* |
| * Make a non-array object with the specified initial state. This method |
| * takes ownership of any extantSlots it is passed. |
| */ |
| static inline JSObject *create(JSContext *cx, |
| js::gc::AllocKind kind, |
| js::gc::InitialHeap heap, |
| js::HandleShape shape, |
| js::HandleTypeObject type, |
| js::HeapSlot *extantSlots = NULL); |
| |
| /* Make an array object with the specified initial state. */ |
| static inline JSObject *createArray(JSContext *cx, |
| js::gc::AllocKind kind, |
| js::gc::InitialHeap heap, |
| js::HandleShape shape, |
| js::HandleTypeObject type, |
| uint32_t length); |
| |
| /* |
| * Remove the last property of an object, provided that it is safe to do so |
| * (the shape and previous shape do not carry conflicting information about |
| * the object itself). |
| */ |
| inline void removeLastProperty(JSContext *cx); |
| inline bool canRemoveLastProperty(); |
| |
| /* |
| * Update the slot span directly for a dictionary object, and allocate |
| * slots to cover the new span if necessary. |
| */ |
| static bool setSlotSpan(JSContext *cx, JS::HandleObject obj, uint32_t span); |
| |
| /* Upper bound on the number of elements in an object. */ |
| static const uint32_t NELEMENTS_LIMIT = JS_BIT(28); |
| |
| public: |
| inline bool setDelegate(JSContext *cx); |
| |
| inline bool isBoundFunction() const; |
| |
| inline bool hasSpecialEquality() const; |
| |
| inline bool watched() const; |
| inline bool setWatched(JSContext *cx); |
| |
| /* See StackFrame::varObj. */ |
| inline bool isVarObj(); |
| inline bool setVarObj(JSContext *cx); |
| |
| /* |
| * Objects with an uncacheable proto can have their prototype mutated |
| * without inducing a shape change on the object. Property cache entries |
| * and JIT inline caches should not be filled for lookups across prototype |
| * lookups on the object. |
| */ |
| inline bool hasUncacheableProto() const; |
| inline bool setUncacheableProto(JSContext *cx); |
| |
| /* |
| * Whether SETLELEM was used to access this object. See also the comment near |
| * PropertyTree::MAX_HEIGHT. |
| */ |
| inline bool hadElementsAccess() const; |
| inline bool setHadElementsAccess(JSContext *cx); |
| |
| public: |
| inline bool nativeEmpty() const; |
| |
| bool shadowingShapeChange(JSContext *cx, const js::Shape &shape); |
| |
| /* |
| * Whether there may be indexed properties on this object, excluding any in |
| * the object's elements. |
| */ |
| inline bool isIndexed() const; |
| |
| inline uint32_t propertyCount() const; |
| |
| inline bool hasShapeTable() const; |
| |
| void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, JS::ObjectsExtraSizes *sizes); |
| |
| bool hasIdempotentProtoChain() const; |
| |
| static const uint32_t MAX_FIXED_SLOTS = 16; |
| |
| public: |
| |
| /* Accessors for properties. */ |
| |
| /* Whether a slot is at a fixed offset from this object. */ |
| inline bool isFixedSlot(size_t slot); |
| |
| /* Index into the dynamic slots array to use for a dynamic slot. */ |
| inline size_t dynamicSlotIndex(size_t slot); |
| |
| /* Get a raw pointer to the object's properties. */ |
| inline const js::HeapSlot *getRawSlots(); |
| |
| /* |
| * Grow or shrink slots immediately before changing the slot span. |
| * The number of allocated slots is not stored explicitly, and changes to |
| * the slots must track changes in the slot span. |
| */ |
| static bool growSlots(JSContext *cx, js::HandleObject obj, uint32_t oldCount, |
| uint32_t newCount); |
| static void shrinkSlots(JSContext *cx, js::HandleObject obj, uint32_t oldCount, |
| uint32_t newCount); |
| |
| bool hasDynamicSlots() const { return slots != NULL; } |
| |
| protected: |
| static inline bool updateSlotsForSpan(JSContext *cx, js::HandleObject obj, size_t oldSpan, |
| size_t newSpan); |
| |
| public: |
| /* |
| * Trigger the write barrier on a range of slots that will no longer be |
| * reachable. |
| */ |
| inline void prepareSlotRangeForOverwrite(size_t start, size_t end); |
| inline void prepareElementRangeForOverwrite(size_t start, size_t end); |
| |
| void rollbackProperties(JSContext *cx, uint32_t slotSpan); |
| |
| inline void nativeSetSlot(uint32_t slot, const js::Value &value); |
| static inline void nativeSetSlotWithType(JSContext *cx, js::HandleObject, js::Shape *shape, |
| const js::Value &value); |
| |
| inline const js::Value &getReservedSlot(uint32_t index) const { |
| JS_ASSERT(index < JSSLOT_FREE(getClass())); |
| return getSlot(index); |
| } |
| |
| inline js::HeapSlot &getReservedSlotRef(uint32_t index) { |
| JS_ASSERT(index < JSSLOT_FREE(getClass())); |
| return getSlotRef(index); |
| } |
| |
| inline void initReservedSlot(uint32_t index, const js::Value &v); |
| inline void setReservedSlot(uint32_t index, const js::Value &v); |
| |
| /* |
| * Marks this object as having a singleton type, and leave the type lazy. |
| * Constructs a new, unique shape for the object. |
| */ |
| static inline bool setSingletonType(JSContext *cx, js::HandleObject obj); |
| |
| inline js::types::TypeObject* getType(JSContext *cx); |
| |
| const js::HeapPtr<js::types::TypeObject> &typeFromGC() const { |
| /* Direct field access for use by GC. */ |
| return type_; |
| } |
| |
| /* |
| * We allow the prototype of an object to be lazily computed if the object |
| * is a proxy. In the lazy case, we store (JSObject *)0x1 in the proto field |
| * of the object's TypeObject. We offer three ways of getting the prototype: |
| * |
| * 1. obj->getProto() returns the prototype, but asserts if obj is a proxy. |
| * 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to |
| * check if the proto is an object, NULL, or lazily computed. |
| * 3. JSObject::getProto(cx, obj, &proto) computes the proto of an object. |
| * If obj is a proxy and the proto is lazy, this code may allocate or |
| * GC in order to compute the proto. Currently, it will not run JS code. |
| */ |
| inline JSObject *getProto() const; |
| static inline bool getProto(JSContext *cx, js::HandleObject obj, |
| js::MutableHandleObject protop); |
| |
| inline void setType(js::types::TypeObject *newType); |
| |
| js::types::TypeObject *getNewType(JSContext *cx, js::Class *clasp, JSFunction *fun = NULL); |
| |
| #ifdef DEBUG |
| bool hasNewType(js::Class *clasp, js::types::TypeObject *newType); |
| #endif |
| |
| /* |
| * Mark an object that has been iterated over and is a singleton. We need |
| * to recover this information in the object's type information after it |
| * is purged on GC. |
| */ |
| inline bool setIteratedSingleton(JSContext *cx); |
| |
| /* |
| * Mark an object as requiring its default 'new' type to have unknown |
| * properties. |
| */ |
| static bool setNewTypeUnknown(JSContext *cx, js::Class *clasp, JS::HandleObject obj); |
| |
| /* Set a new prototype for an object with a singleton type. */ |
| bool splicePrototype(JSContext *cx, js::Class *clasp, js::Handle<js::TaggedProto> proto); |
| |
| /* |
| * For bootstrapping, whether to splice a prototype for Function.prototype |
| * or the global object. |
| */ |
| bool shouldSplicePrototype(JSContext *cx); |
| |
| /* |
| * Parents and scope chains. |
| * |
| * All script-accessible objects with a NULL parent are global objects, |
| * and all global objects have a NULL parent. Some builtin objects which |
| * are not script-accessible also have a NULL parent, such as parser |
| * created functions for non-compileAndGo scripts. |
| * |
| * Except for the non-script-accessible builtins, the global with which an |
| * object is associated can be reached by following parent links to that |
| * global (see global()). |
| * |
| * The scope chain of an object is the link in the search path when a |
| * script does a name lookup on a scope object. For JS internal scope |
| * objects --- Call, DeclEnv and Block --- the chain is stored in |
| * the first fixed slot of the object, and the object's parent is the |
| * associated global. For other scope objects, the chain is stored in the |
| * object's parent. |
| * |
| * In compileAndGo code, scope chains can contain only internal scope |
| * objects with a global object at the root as the scope of the outermost |
| * non-function script. In non-compileAndGo code, the scope of the |
| * outermost non-function script might not be a global object, and can have |
| * a mix of other objects above it before the global object is reached. |
| */ |
| |
| /* Access the parent link of an object. */ |
| inline JSObject *getParent() const; |
| static bool setParent(JSContext *cx, js::HandleObject obj, js::HandleObject newParent); |
| |
| /* |
| * Get the enclosing scope of an object. When called on non-scope object, |
| * this will just be the global (the name "enclosing scope" still applies |
| * in this situation because non-scope objects can be on the scope chain). |
| */ |
| inline JSObject *enclosingScope(); |
| |
| /* Access the metadata on an object. */ |
| inline JSObject *getMetadata() const; |
| static bool setMetadata(JSContext *cx, js::HandleObject obj, js::HandleObject newMetadata); |
| |
| inline js::GlobalObject &global() const; |
| |
| /* Remove the type (and prototype) or parent from a new object. */ |
| static inline bool clearType(JSContext *cx, js::HandleObject obj); |
| static bool clearParent(JSContext *cx, js::HandleObject obj); |
| |
| /* |
| * ES5 meta-object properties and operations. |
| */ |
| |
| private: |
| enum ImmutabilityType { SEAL, FREEZE }; |
| |
| /* |
| * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the |
| * object as non-extensible, and adjust each property's attributes appropriately: each |
| * property becomes non-configurable, and if |freeze|, data properties become |
| * read-only as well. |
| */ |
| static bool sealOrFreeze(JSContext *cx, js::HandleObject obj, ImmutabilityType it); |
| |
| static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp); |
| |
| static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it); |
| |
| public: |
| /* ES5 15.2.3.8: non-extensible, all props non-configurable */ |
| static inline bool seal(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, SEAL); } |
| /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */ |
| static inline bool freeze(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, FREEZE); } |
| |
| static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) { |
| return isSealedOrFrozen(cx, obj, SEAL, resultp); |
| } |
| static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) { |
| return isSealedOrFrozen(cx, obj, FREEZE, resultp); |
| } |
| |
| /* toString support. */ |
| static const char *className(JSContext *cx, js::HandleObject obj); |
| |
| /* Accessors for elements. */ |
| inline bool ensureElements(JSContext *cx, uint32_t cap); |
| bool growElements(js::ThreadSafeContext *tcx, uint32_t newcap); |
| void shrinkElements(JSContext *cx, uint32_t cap); |
| inline void setDynamicElements(js::ObjectElements *header); |
| |
| inline uint32_t getDenseCapacity(); |
| inline void setDenseInitializedLength(uint32_t length); |
| inline void ensureDenseInitializedLength(JSContext *cx, uint32_t index, uint32_t extra); |
| inline void setDenseElement(uint32_t index, const js::Value &val); |
| inline void initDenseElement(uint32_t index, const js::Value &val); |
| inline void setDenseElementMaybeConvertDouble(uint32_t index, const js::Value &val); |
| static inline void setDenseElementWithType(JSContext *cx, js::HandleObject obj, |
| uint32_t index, const js::Value &val); |
| static inline void initDenseElementWithType(JSContext *cx, js::HandleObject obj, |
| uint32_t index, const js::Value &val); |
| static inline void setDenseElementHole(JSContext *cx, js::HandleObject obj, uint32_t index); |
| static inline void removeDenseElementForSparseIndex(JSContext *cx, js::HandleObject obj, |
| uint32_t index); |
| inline void copyDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count); |
| inline void initDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count); |
| inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count); |
| inline void moveDenseElementsUnbarriered(uint32_t dstStart, uint32_t srcStart, uint32_t count); |
| inline bool shouldConvertDoubleElements(); |
| inline void setShouldConvertDoubleElements(); |
| |
| /* Packed information for this object's elements. */ |
| inline void markDenseElementsNotPacked(JSContext *cx); |
| |
| /* |
| * ensureDenseElements ensures that the object can hold at least |
| * index + extra elements. It returns ED_OK on success, ED_FAILED on |
| * failure to grow the array, ED_SPARSE when the object is too sparse to |
| * grow (this includes the case of index + extra overflow). In the last |
| * two cases the object is kept intact. |
| */ |
| enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE }; |
| inline EnsureDenseResult ensureDenseElements(JSContext *cx, uint32_t index, uint32_t extra); |
| inline EnsureDenseResult parExtendDenseElements(js::ThreadSafeContext *tcx, js::Value *v, |
| uint32_t extra); |
| |
| inline EnsureDenseResult extendDenseElements(js::ThreadSafeContext *tcx, |
| uint32_t requiredCapacity, uint32_t extra); |
| |
| /* Convert a single dense element to a sparse property. */ |
| static bool sparsifyDenseElement(JSContext *cx, js::HandleObject obj, uint32_t index); |
| |
| /* Convert all dense elements to sparse properties. */ |
| static bool sparsifyDenseElements(JSContext *cx, js::HandleObject obj); |
| |
| /* Small objects are dense, no matter what. */ |
| static const uint32_t MIN_SPARSE_INDEX = 1000; |
| |
| /* |
| * Element storage for an object will be sparse if fewer than 1/8 indexes |
| * are filled in. |
| */ |
| static const unsigned SPARSE_DENSITY_RATIO = 8; |
| |
| /* |
| * Check if after growing the object's elements will be too sparse. |
| * newElementsHint is an estimated number of elements to be added. |
| */ |
| bool willBeSparseElements(uint32_t requiredCapacity, uint32_t newElementsHint); |
| |
| /* |
| * After adding a sparse index to obj, see if it should be converted to use |
| * dense elements. |
| */ |
| static EnsureDenseResult maybeDensifySparseElements(JSContext *cx, js::HandleObject obj); |
| |
| /* Array specific accessors. */ |
| inline bool arrayLengthIsWritable() const; |
| inline uint32_t getArrayLength() const; |
| static inline void setArrayLength(JSContext *cx, js::HandleObject obj, uint32_t length); |
| inline void setArrayLengthInt32(uint32_t length); |
| |
| public: |
| /* |
| * Date-specific getters and setters. |
| */ |
| |
| static const uint32_t JSSLOT_DATE_UTC_TIME = 0; |
| static const uint32_t JSSLOT_DATE_TZA = 1; |
| |
| /* |
| * Cached slots holding local properties of the date. |
| * These are undefined until the first actual lookup occurs |
| * and are reset to undefined whenever the date's time is modified. |
| */ |
| static const uint32_t JSSLOT_DATE_COMPONENTS_START = 2; |
| |
| static const uint32_t JSSLOT_DATE_LOCAL_TIME = JSSLOT_DATE_COMPONENTS_START + 0; |
| static const uint32_t JSSLOT_DATE_LOCAL_YEAR = JSSLOT_DATE_COMPONENTS_START + 1; |
| static const uint32_t JSSLOT_DATE_LOCAL_MONTH = JSSLOT_DATE_COMPONENTS_START + 2; |
| static const uint32_t JSSLOT_DATE_LOCAL_DATE = JSSLOT_DATE_COMPONENTS_START + 3; |
| static const uint32_t JSSLOT_DATE_LOCAL_DAY = JSSLOT_DATE_COMPONENTS_START + 4; |
| static const uint32_t JSSLOT_DATE_LOCAL_HOURS = JSSLOT_DATE_COMPONENTS_START + 5; |
| static const uint32_t JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_DATE_COMPONENTS_START + 6; |
| static const uint32_t JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_DATE_COMPONENTS_START + 7; |
| |
| static const uint32_t DATE_CLASS_RESERVED_SLOTS = JSSLOT_DATE_LOCAL_SECONDS + 1; |
| |
| inline const js::Value &getDateUTCTime() const; |
| inline void setDateUTCTime(const js::Value &pthis); |
| |
| public: |
| /* |
| * Iterator-specific getters and setters. |
| */ |
| |
| static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1; |
| |
| /* |
| * Back to generic stuff. |
| */ |
| inline bool isCallable(); |
| |
| inline void finish(js::FreeOp *fop); |
| JS_ALWAYS_INLINE void finalize(js::FreeOp *fop); |
| |
| static inline bool hasProperty(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, bool *foundp, unsigned flags = 0); |
| |
| /* |
| * Allocate and free an object slot. |
| * |
| * FIXME: bug 593129 -- slot allocation should be done by object methods |
| * after calling object-parameter-free shape methods, avoiding coupling |
| * logic across the object vs. shape module wall. |
| */ |
| static bool allocSlot(JSContext *cx, JS::HandleObject obj, uint32_t *slotp); |
| void freeSlot(uint32_t slot); |
| |
| public: |
| static bool reportReadOnly(JSContext *cx, jsid id, unsigned report = JSREPORT_ERROR); |
| bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); |
| bool reportNotExtensible(JSContext *cx, unsigned report = JSREPORT_ERROR); |
| |
| /* |
| * Get the property with the given id, then call it as a function with the |
| * given arguments, providing this object as |this|. If the property isn't |
| * callable a TypeError will be thrown. On success the value returned by |
| * the call is stored in *vp. |
| */ |
| bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv, |
| js::MutableHandleValue vp); |
| |
| private: |
| static js::Shape *getChildProperty(JSContext *cx, JS::HandleObject obj, |
| js::HandleShape parent, js::StackShape &child); |
| |
| protected: |
| /* |
| * Internal helper that adds a shape not yet mapped by this object. |
| * |
| * Notes: |
| * 1. getter and setter must be normalized based on flags (see jsscope.cpp). |
| * 2. !isExtensible() checking must be done by callers. |
| */ |
| static js::Shape *addPropertyInternal(JSContext *cx, |
| JS::HandleObject obj, JS::HandleId id, |
| JSPropertyOp getter, JSStrictPropertyOp setter, |
| uint32_t slot, unsigned attrs, |
| unsigned flags, int shortid, js::Shape **spp, |
| bool allowDictionary); |
| |
| private: |
| struct TradeGutsReserved; |
| static bool ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b, |
| TradeGutsReserved &reserved); |
| |
| static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b, |
| TradeGutsReserved &reserved); |
| |
| public: |
| /* Add a property whose id is not yet in this scope. */ |
| static js::Shape *addProperty(JSContext *cx, JS::HandleObject, JS::HandleId id, |
| JSPropertyOp getter, JSStrictPropertyOp setter, |
| uint32_t slot, unsigned attrs, unsigned flags, |
| int shortid, bool allowDictionary = true); |
| |
| /* Add a data property whose id is not yet in this scope. */ |
| js::Shape *addDataProperty(JSContext *cx, jsid id_, uint32_t slot, unsigned attrs) { |
| JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); |
| JS::RootedObject self(cx, this); |
| JS::RootedId id(cx, id_); |
| return addProperty(cx, self, id, NULL, NULL, slot, attrs, 0, 0); |
| } |
| |
| js::Shape *addDataProperty(JSContext *cx, js::HandlePropertyName name, uint32_t slot, unsigned attrs) { |
| JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); |
| JS::RootedObject self(cx, this); |
| JS::RootedId id(cx, NameToId(name)); |
| return addProperty(cx, self, id, NULL, NULL, slot, attrs, 0, 0); |
| } |
| |
| /* Add or overwrite a property for id in this scope. */ |
| static js::Shape *putProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, |
| JSPropertyOp getter, JSStrictPropertyOp setter, |
| uint32_t slot, unsigned attrs, |
| unsigned flags, int shortid); |
| static js::Shape *putProperty(JSContext *cx, JS::HandleObject obj, |
| js::PropertyName *name, |
| JSPropertyOp getter, JSStrictPropertyOp setter, |
| uint32_t slot, unsigned attrs, |
| unsigned flags, int shortid) |
| { |
| JS::RootedId id(cx, js::NameToId(name)); |
| return putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid); |
| } |
| |
| /* Change the given property into a sibling with the same id in this scope. */ |
| static js::Shape *changeProperty(JSContext *cx, js::HandleObject obj, |
| js::HandleShape shape, unsigned attrs, unsigned mask, |
| JSPropertyOp getter, JSStrictPropertyOp setter); |
| |
| static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj, |
| js::HandleShape shape, unsigned attrs); |
| |
| /* Remove the property named by id from this object. */ |
| bool removeProperty(JSContext *cx, jsid id); |
| |
| /* Clear the scope, making it empty. */ |
| static void clear(JSContext *cx, js::HandleObject obj); |
| |
| static inline JSBool lookupGeneric(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, |
| js::MutableHandleObject objp, js::MutableHandleShape propp); |
| static inline JSBool lookupProperty(JSContext *cx, js::HandleObject obj, |
| js::PropertyName *name, |
| js::MutableHandleObject objp, js::MutableHandleShape propp); |
| static inline JSBool lookupElement(JSContext *cx, js::HandleObject obj, |
| uint32_t index, |
| js::MutableHandleObject objp, js::MutableHandleShape propp); |
| static inline JSBool lookupSpecial(JSContext *cx, js::HandleObject obj, |
| js::SpecialId sid, |
| js::MutableHandleObject objp, js::MutableHandleShape propp); |
| |
| static inline JSBool defineGeneric(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, js::HandleValue value, |
| JSPropertyOp getter = JS_PropertyStub, |
| JSStrictPropertyOp setter = JS_StrictPropertyStub, |
| unsigned attrs = JSPROP_ENUMERATE); |
| static inline JSBool defineProperty(JSContext *cx, js::HandleObject obj, |
| js::PropertyName *name, js::HandleValue value, |
| JSPropertyOp getter = JS_PropertyStub, |
| JSStrictPropertyOp setter = JS_StrictPropertyStub, |
| unsigned attrs = JSPROP_ENUMERATE); |
| |
| static inline JSBool defineElement(JSContext *cx, js::HandleObject obj, |
| uint32_t index, js::HandleValue value, |
| JSPropertyOp getter = JS_PropertyStub, |
| JSStrictPropertyOp setter = JS_StrictPropertyStub, |
| unsigned attrs = JSPROP_ENUMERATE); |
| static inline JSBool defineSpecial(JSContext *cx, js::HandleObject obj, |
| js::SpecialId sid, js::HandleValue value, |
| JSPropertyOp getter = JS_PropertyStub, |
| JSStrictPropertyOp setter = JS_StrictPropertyStub, |
| unsigned attrs = JSPROP_ENUMERATE); |
| |
| static inline JSBool getGeneric(JSContext *cx, js::HandleObject obj, |
| js::HandleObject receiver, |
| js::HandleId id, js::MutableHandleValue vp); |
| static inline JSBool getGenericNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, |
| jsid id, js::Value *vp); |
| static inline JSBool getProperty(JSContext *cx, js::HandleObject obj, |
| js::HandleObject receiver, |
| js::PropertyName *name, js::MutableHandleValue vp); |
| static inline JSBool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, |
| js::PropertyName *name, js::Value *vp); |
| static inline JSBool getElement(JSContext *cx, js::HandleObject obj, |
| js::HandleObject receiver, |
| uint32_t index, js::MutableHandleValue vp); |
| static inline JSBool getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, |
| uint32_t index, js::Value *vp); |
| /* If element is not present (e.g. array hole) *present is set to |
| false and the contents of *vp are unusable garbage. */ |
| static inline JSBool getElementIfPresent(JSContext *cx, js::HandleObject obj, |
| js::HandleObject receiver, uint32_t index, |
| js::MutableHandleValue vp, bool *present); |
| static inline JSBool getSpecial(JSContext *cx, js::HandleObject obj, |
| js::HandleObject receiver, js::SpecialId sid, |
| js::MutableHandleValue vp); |
| |
| static inline JSBool setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, |
| js::HandleId id, |
| js::MutableHandleValue vp, JSBool strict); |
| static inline JSBool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, |
| js::PropertyName *name, |
| js::MutableHandleValue vp, JSBool strict); |
| static inline JSBool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, |
| uint32_t index, |
| js::MutableHandleValue vp, JSBool strict); |
| static inline JSBool setSpecial(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, |
| js::SpecialId sid, |
| js::MutableHandleValue vp, JSBool strict); |
| |
| static JSBool nonNativeSetProperty(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, js::MutableHandleValue vp, JSBool strict); |
| static JSBool nonNativeSetElement(JSContext *cx, js::HandleObject obj, |
| uint32_t index, js::MutableHandleValue vp, JSBool strict); |
| |
| static inline JSBool getGenericAttributes(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, unsigned *attrsp); |
| static inline JSBool getPropertyAttributes(JSContext *cx, js::HandleObject obj, |
| js::PropertyName *name, unsigned *attrsp); |
| static inline JSBool getElementAttributes(JSContext *cx, js::HandleObject obj, |
| uint32_t index, unsigned *attrsp); |
| static inline JSBool getSpecialAttributes(JSContext *cx, js::HandleObject obj, |
| js::SpecialId sid, unsigned *attrsp); |
| |
| static inline JSBool setGenericAttributes(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, unsigned *attrsp); |
| static inline JSBool setPropertyAttributes(JSContext *cx, js::HandleObject obj, |
| js::PropertyName *name, unsigned *attrsp); |
| static inline JSBool setElementAttributes(JSContext *cx, js::HandleObject obj, |
| uint32_t index, unsigned *attrsp); |
| static inline JSBool setSpecialAttributes(JSContext *cx, js::HandleObject obj, |
| js::SpecialId sid, unsigned *attrsp); |
| |
| static inline bool deleteProperty(JSContext *cx, js::HandleObject obj, |
| js::HandlePropertyName name, |
| JSBool *succeeded); |
| static inline bool deleteElement(JSContext *cx, js::HandleObject obj, |
| uint32_t index, JSBool *succeeded); |
| static inline bool deleteSpecial(JSContext *cx, js::HandleObject obj, |
| js::HandleSpecialId sid, JSBool *succeeded); |
| static bool deleteByValue(JSContext *cx, js::HandleObject obj, |
| const js::Value &property, JSBool *succeeded); |
| |
| static inline bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, |
| JS::MutableHandleValue statep, JS::MutableHandleId idp); |
| static inline bool defaultValue(JSContext *cx, js::HandleObject obj, |
| JSType hint, js::MutableHandleValue vp); |
| static inline JSObject *thisObject(JSContext *cx, js::HandleObject obj); |
| |
| static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp); |
| |
| static bool swap(JSContext *cx, JS::HandleObject a, JS::HandleObject b); |
| |
| inline void initArrayClass(); |
| |
| /* |
| * In addition to the generic object interface provided by JSObject, |
| * specific types of objects may provide additional operations. To access, |
| * these addition operations, callers should use the pattern: |
| * |
| * if (obj.is<XObject>()) { |
| * XObject &x = obj.as<XObject>(); |
| * x.foo(); |
| * } |
| * |
| * These XObject classes form a hierarchy. For example, for a cloned block |
| * object, the following predicates are true: is<ClonedBlockObject>, |
| * is<BlockObject>, is<NestedScopeObject> and is<ScopeObject>. Each of |
| * these has a respective class that derives and adds operations. |
| * |
| * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file |
| * triplet (along with any class YObject that derives XObject). |
| * |
| * Note that X represents a low-level representation and does not query the |
| * [[Class]] property of object defined by the spec (for this, see |
| * js::ObjectClassIs). |
| * |
| * SpiderMonkey has not been completely switched to the is/as/XObject |
| * pattern so in some cases there is no XObject class and the engine |
| * instead pokes directly at reserved slots and getPrivate. In such cases, |
| * consider adding the missing XObject class. |
| */ |
| |
| template <class T> |
| inline bool is() const { return getClass() == &T::class_; } |
| |
| template <class T> |
| T &as() { |
| JS_ASSERT(is<T>()); |
| return *static_cast<T *>(this); |
| } |
| |
| template <class T> |
| const T &as() const { |
| JS_ASSERT(is<T>()); |
| return *static_cast<const T *>(this); |
| } |
| |
| /* Direct subtypes of JSObject: */ |
| inline bool isArray() const { return hasClass(&js::ArrayClass); } |
| inline bool isDate() const { return hasClass(&js::DateClass); } |
| inline bool isError() const { return hasClass(&js::ErrorClass); } |
| inline bool isObject() const { return hasClass(&js::ObjectClass); } |
| using js::ObjectImpl::isProxy; |
| inline bool isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); } |
| inline bool isTypedArray() const; |
| |
| /* Subtypes of Proxy. */ |
| inline bool isWrapper() const; |
| inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); } |
| inline bool isCrossCompartmentWrapper() const; |
| |
| static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; } |
| |
| #ifdef DEBUG |
| void dump(); |
| #endif |
| |
| private: |
| static void staticAsserts() { |
| MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object), |
| "shadow interface must match actual interface"); |
| MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::ObjectImpl), |
| "JSObject itself must not have any fields"); |
| MOZ_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0, |
| "fixed slots after an object must be aligned"); |
| } |
| |
| JSObject() MOZ_DELETE; |
| JSObject(const JSObject &other) MOZ_DELETE; |
| void operator=(const JSObject &other) MOZ_DELETE; |
| }; |
| |
| /* |
| * The only sensible way to compare JSObject with == is by identity. We use |
| * const& instead of * as a syntactic way to assert non-null. This leads to an |
| * abundance of address-of operators to identity. Hence this overload. |
| */ |
| static JS_ALWAYS_INLINE bool |
| operator==(const JSObject &lhs, const JSObject &rhs) |
| { |
| return &lhs == &rhs; |
| } |
| |
| static JS_ALWAYS_INLINE bool |
| operator!=(const JSObject &lhs, const JSObject &rhs) |
| { |
| return &lhs != &rhs; |
| } |
| |
| struct JSObject_Slots2 : JSObject { js::Value fslots[2]; }; |
| struct JSObject_Slots4 : JSObject { js::Value fslots[4]; }; |
| struct JSObject_Slots8 : JSObject { js::Value fslots[8]; }; |
| struct JSObject_Slots12 : JSObject { js::Value fslots[12]; }; |
| struct JSObject_Slots16 : JSObject { js::Value fslots[16]; }; |
| |
| class JSValueArray { |
| public: |
| jsval *array; |
| size_t length; |
| |
| JSValueArray(jsval *v, size_t c) : array(v), length(c) {} |
| }; |
| |
| class ValueArray { |
| public: |
| js::Value *array; |
| size_t length; |
| |
| ValueArray(js::Value *v, size_t c) : array(v), length(c) {} |
| }; |
| |
| namespace js { |
| |
| template <AllowGC allowGC> |
| extern JSBool |
| HasOwnProperty(JSContext *cx, LookupGenericOp lookup, |
| typename MaybeRooted<JSObject*, allowGC>::HandleType obj, |
| typename MaybeRooted<jsid, allowGC>::HandleType id, |
| typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp, |
| typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp); |
| |
| bool |
| IsStandardClassResolved(JSObject *obj, js::Class *clasp); |
| |
| void |
| MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp); |
| |
| } /* namespace js */ |
| |
| /* |
| * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp. |
| */ |
| extern const char js_watch_str[]; |
| extern const char js_unwatch_str[]; |
| extern const char js_hasOwnProperty_str[]; |
| extern const char js_isPrototypeOf_str[]; |
| extern const char js_propertyIsEnumerable_str[]; |
| |
| #ifdef OLD_GETTER_SETTER_METHODS |
| extern const char js_defineGetter_str[]; |
| extern const char js_defineSetter_str[]; |
| extern const char js_lookupGetter_str[]; |
| extern const char js_lookupSetter_str[]; |
| #endif |
| |
| extern JSBool |
| js_PopulateObject(JSContext *cx, js::HandleObject newborn, js::HandleObject props); |
| |
| /* |
| * Fast access to immutable standard objects (constructors and prototypes). |
| */ |
| extern bool |
| js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, |
| js::MutableHandleObject objp); |
| |
| /* |
| * Determine if the given object is a prototype for a standard class. If so, |
| * return the associated JSProtoKey. If not, return JSProto_Null. |
| */ |
| extern JSProtoKey |
| js_IdentifyClassPrototype(JSObject *obj); |
| |
| /* |
| * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is |
| * JSProto_Null, clasp must non-null. |
| */ |
| bool |
| js_FindClassObject(JSContext *cx, JSProtoKey protoKey, js::MutableHandleValue vp, |
| js::Class *clasp = NULL); |
| |
| /* |
| * Find or create a property named by id in obj's scope, with the given getter |
| * and setter, slot, attributes, and other members. |
| */ |
| extern js::Shape * |
| js_AddNativeProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, |
| JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot, |
| unsigned attrs, unsigned flags, int shortid); |
| |
| namespace js { |
| |
| extern JSBool |
| DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, |
| JS::HandleValue descriptor, JSBool *bp); |
| |
| extern JSBool |
| DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, |
| const js::PropertyDescriptor &descriptor, JSBool *bp); |
| |
| /* |
| * The NewObjectKind allows an allocation site to specify the type properties |
| * and lifetime requirements that must be fixed at allocation time. |
| */ |
| enum NewObjectKind { |
| /* This is the default. Most objects are generic. */ |
| GenericObject, |
| |
| /* |
| * Singleton objects are treated specially by the type system. This flag |
| * ensures that the new object is automatically set up correctly as a |
| * singleton and is allocated in the correct heap. |
| */ |
| SingletonObject, |
| |
| /* |
| * Objects which may be marked as a singleton after allocation must still |
| * be allocated on the correct heap, but are not automatically setup as a |
| * singleton after allocation. |
| */ |
| MaybeSingletonObject, |
| |
| /* |
| * Objects which will not benefit from being allocated in the nursery |
| * (e.g. because they are known to have a long lifetime) may be allocated |
| * with this kind to place them immediately into the tenured generation. |
| */ |
| TenuredObject |
| }; |
| |
| inline gc::InitialHeap |
| GetInitialHeap(NewObjectKind newKind, const Class *clasp) |
| { |
| if (clasp->finalize || newKind != GenericObject) |
| return gc::TenuredHeap; |
| return gc::DefaultHeap; |
| } |
| |
| // Specialized call for constructing |this| with a known function callee, |
| // and a known prototype. |
| extern JSObject * |
| CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto, |
| NewObjectKind newKind = GenericObject); |
| |
| // Specialized call for constructing |this| with a known function callee. |
| extern JSObject * |
| CreateThisForFunction(JSContext *cx, js::HandleObject callee, bool newType); |
| |
| // Generic call for constructing |this|. |
| extern JSObject * |
| CreateThis(JSContext *cx, js::Class *clasp, js::HandleObject callee); |
| |
| extern JSObject * |
| CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent); |
| |
| /* |
| * Flags for the defineHow parameter of js_DefineNativeProperty. |
| */ |
| const unsigned DNP_DONT_PURGE = 1; /* suppress js_PurgeScopeChain */ |
| const unsigned DNP_UNQUALIFIED = 2; /* Unqualified property set. Only used in |
| the defineHow argument of |
| js_SetPropertyHelper. */ |
| const unsigned DNP_SKIP_TYPE = 4; /* Don't update type information */ |
| |
| /* |
| * Return successfully added or changed shape or NULL on error. |
| */ |
| extern bool |
| DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, |
| PropertyOp getter, StrictPropertyOp setter, unsigned attrs, |
| unsigned flags, int shortid, unsigned defineHow = 0); |
| |
| inline bool |
| DefineNativeProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue value, |
| PropertyOp getter, StrictPropertyOp setter, unsigned attrs, |
| unsigned flags, int shortid, unsigned defineHow = 0) |
| { |
| Rooted<jsid> id(cx, NameToId(name)); |
| return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, flags, |
| shortid, defineHow); |
| } |
| |
| /* |
| * Specialized subroutine that allows caller to preset JSRESOLVE_* flags. |
| */ |
| extern bool |
| LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, |
| js::MutableHandleObject objp, js::MutableHandleShape propp); |
| |
| inline bool |
| LookupPropertyWithFlags(JSContext *cx, HandleObject obj, PropertyName *name, unsigned flags, |
| js::MutableHandleObject objp, js::MutableHandleShape propp) |
| { |
| Rooted<jsid> id(cx, NameToId(name)); |
| return LookupPropertyWithFlags(cx, obj, id, flags, objp, propp); |
| } |
| |
| /* |
| * Call the [[DefineOwnProperty]] internal method of obj. |
| * |
| * If obj is an array, this follows ES5 15.4.5.1. |
| * If obj is any other native object, this follows ES5 8.12.9. |
| * If obj is a proxy, this calls the proxy handler's defineProperty method. |
| * Otherwise, this reports an error and returns false. |
| */ |
| extern bool |
| DefineProperty(JSContext *cx, js::HandleObject obj, |
| js::HandleId id, const PropDesc &desc, bool throwError, |
| bool *rval); |
| |
| /* |
| * Read property descriptors from props, as for Object.defineProperties. See |
| * ES5 15.2.3.7 steps 3-5. |
| */ |
| extern bool |
| ReadPropertyDescriptors(JSContext *cx, HandleObject props, bool checkAccessors, |
| AutoIdVector *ids, AutoPropDescArrayRooter *descs); |
| |
| /* |
| * Constant to pass to js_LookupPropertyWithFlags to infer bits from current |
| * bytecode. |
| */ |
| static const unsigned RESOLVE_INFER = 0xffff; |
| |
| /* Read the name using a dynamic lookup on the scopeChain. */ |
| extern bool |
| LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, |
| MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp); |
| |
| extern bool |
| LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain, |
| JSObject **objp, JSObject **pobjp, Shape **propp); |
| |
| /* |
| * Like LookupName except returns the global object if 'name' is not found in |
| * any preceding non-global scope. |
| * |
| * Additionally, pobjp and propp are not needed by callers so they are not |
| * returned. |
| */ |
| extern bool |
| LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, |
| MutableHandleObject objp); |
| |
| } |
| |
| extern JSObject * |
| js_FindVariableScope(JSContext *cx, JSFunction **funp); |
| |
| /* |
| * NB: js_NativeGet and js_NativeSet are called with the scope containing shape |
| * (pobj's scope for Get, obj's for Set) locked, and on successful return, that |
| * scope is again locked. But on failure, both functions return false with the |
| * scope containing shape unlocked. |
| */ |
| extern JSBool |
| js_NativeGet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> pobj, |
| js::Handle<js::Shape*> shape, unsigned getHow, js::MutableHandle<js::Value> vp); |
| |
| extern JSBool |
| js_NativeSet(JSContext *cx, js::Handle<JSObject*> obj, js::Handle<JSObject*> receiver, |
| js::Handle<js::Shape*> shape, bool strict, js::MutableHandleValue vp); |
| |
| namespace js { |
| |
| bool |
| GetPropertyHelper(JSContext *cx, HandleObject obj, HandleId id, uint32_t getHow, MutableHandleValue vp); |
| |
| inline bool |
| GetPropertyHelper(JSContext *cx, HandleObject obj, PropertyName *name, uint32_t getHow, MutableHandleValue vp) |
| { |
| RootedId id(cx, NameToId(name)); |
| return GetPropertyHelper(cx, obj, id, getHow, vp); |
| } |
| |
| bool |
| LookupPropertyPure(JSObject *obj, jsid id, JSObject **objp, Shape **propp); |
| |
| bool |
| GetPropertyPure(JSObject *obj, jsid id, Value *vp); |
| |
| inline bool |
| GetPropertyPure(JSObject *obj, PropertyName *name, Value *vp) |
| { |
| return GetPropertyPure(obj, NameToId(name), vp); |
| } |
| |
| bool |
| GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc); |
| |
| bool |
| GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp); |
| |
| bool |
| NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, MutableHandleValue vp); |
| |
| /* |
| * If obj has an already-resolved data property for id, return true and |
| * store the property value in *vp. |
| */ |
| extern bool |
| HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp); |
| |
| inline bool |
| HasDataProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp) |
| { |
| return HasDataProperty(cx, obj, NameToId(name), vp); |
| } |
| |
| extern JSBool |
| CheckAccess(JSContext *cx, JSObject *obj, HandleId id, JSAccessMode mode, |
| MutableHandleValue v, unsigned *attrsp); |
| |
| extern bool |
| IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result); |
| |
| } /* namespace js */ |
| |
| /* |
| * Wrap boolean, number or string as Boolean, Number or String object. |
| * *vp must not be an object, null or undefined. |
| */ |
| extern JSBool |
| js_PrimitiveToObject(JSContext *cx, js::Value *vp); |
| |
| extern JSBool |
| js_ValueToObjectOrNull(JSContext *cx, const js::Value &v, JS::MutableHandleObject objp); |
| |
| /* Throws if v could not be converted to an object. */ |
| extern JSObject * |
| js_ValueToNonNullObject(JSContext *cx, const js::Value &v); |
| |
| namespace js { |
| |
| /* |
| * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might |
| * already be an object, use ToObject. reportCantConvert controls how null and |
| * undefined errors are reported. |
| */ |
| extern JSObject * |
| ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack); |
| |
| /* For object conversion in e.g. native functions. */ |
| JS_ALWAYS_INLINE JSObject * |
| ToObject(JSContext *cx, HandleValue vp) |
| { |
| if (vp.isObject()) |
| return &vp.toObject(); |
| return ToObjectSlow(cx, vp, false); |
| } |
| |
| /* For converting stack values to objects. */ |
| JS_ALWAYS_INLINE JSObject * |
| ToObjectFromStack(JSContext *cx, HandleValue vp) |
| { |
| if (vp.isObject()) |
| return &vp.toObject(); |
| return ToObjectSlow(cx, vp, true); |
| } |
| |
| extern JSObject * |
| CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj); |
| |
| } /* namespace js */ |
| |
| extern void |
| js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize); |
| |
| extern JSBool |
| js_ReportGetterOnlyAssignment(JSContext *cx); |
| |
| extern unsigned |
| js_InferFlags(JSContext *cx, unsigned defaultFlags); |
| |
| |
| /* |
| * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is |
| * JSProto_Null, clasp must non-null. |
| * |
| * If protoKey is constant and scope is non-null, use GlobalObject's prototype |
| * methods instead. |
| */ |
| extern bool |
| js_GetClassPrototype(JSContext *cx, JSProtoKey protoKey, js::MutableHandleObject protop, |
| js::Class *clasp = NULL); |
| |
| namespace js { |
| |
| extern bool |
| SetClassAndProto(JSContext *cx, HandleObject obj, |
| Class *clasp, Handle<TaggedProto> proto, bool checkForCycles); |
| |
| extern JSObject * |
| NonNullObject(JSContext *cx, const Value &v); |
| |
| extern const char * |
| InformalValueTypeName(const Value &v); |
| |
| inline void |
| DestroyIdArray(FreeOp *fop, JSIdArray *ida); |
| |
| extern bool |
| GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method, |
| MutableHandleObject objp); |
| |
| /* Helpers for throwing. These always return false. */ |
| extern bool |
| Throw(JSContext *cx, jsid id, unsigned errorNumber); |
| |
| extern bool |
| Throw(JSContext *cx, JSObject *obj, unsigned errorNumber); |
| |
| /* |
| * Helper function. To approximate a call to the [[DefineOwnProperty]] internal |
| * method described in ES5, first call this, then call JS_DefinePropertyById. |
| * |
| * JS_DefinePropertyById by itself does not enforce the invariants on |
| * non-configurable properties when obj->isNative(). This function performs the |
| * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11), |
| * but only if obj is native. |
| * |
| * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as |
| * a sort of extension point, but there is no hook in js::Class, |
| * js::ProxyHandler, or the JSAPI with precisely the right semantics for it. |
| */ |
| extern bool |
| CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, |
| PropertyOp getter, StrictPropertyOp setter, unsigned attrs); |
| |
| } /* namespace js */ |
| |
| #endif /* jsobj_h */ |