Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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)
1002 {
1003 JS::RootedId id(cx, js::NameToId(name));
1004 return getGeneric(cx, obj, receiver, id, vp);
1005 }
1007 static bool getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver,
1008 js::PropertyName *name, js::Value *vp)
1009 {
1010 return getGenericNoGC(cx, obj, receiver, js::NameToId(name), vp);
1011 }
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)
1020 {
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);
1025 }
1027 static bool setProperty(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
1028 js::PropertyName *name,
1029 js::MutableHandleValue vp, bool strict)
1030 {
1031 JS::RootedId id(cx, js::NameToId(name));
1032 return setGeneric(cx, obj, receiver, id, vp, strict);
1033 }
1035 static bool setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
1036 uint32_t index, js::MutableHandleValue vp, bool strict)
1037 {
1038 if (obj->getOps()->setElement)
1039 return nonNativeSetElement(cx, obj, index, vp, strict);
1040 return js::baseops::SetElementHelper(cx, obj, receiver, index, vp, strict);
1041 }
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)
1050 {
1051 js::GenericAttributesOp op = obj->getOps()->getGenericAttributes;
1052 return (op ? op : js::baseops::GetAttributes)(cx, obj, id, attrsp);
1053 }
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)
1072 {
1073 JSNewEnumerateOp op = obj->getOps()->enumerate;
1074 return (op ? op : JS_EnumerateState)(cx, obj, iterop, statep, idp);
1075 }
1077 static bool defaultValue(JSContext *cx, js::HandleObject obj, JSType hint,
1078 js::MutableHandleValue vp)
1079 {
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;
1088 }
1090 static JSObject *thisObject(JSContext *cx, js::HandleObject obj)
1091 {
1092 JSObjectOp op = obj->getOps()->thisObject;
1093 return op ? op(cx, obj) : obj;
1094 }
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:
1106 *
1107 * if (obj.is<XObject>()) {
1108 * XObject &x = obj.as<XObject>();
1109 * x.foo();
1110 * }
1111 *
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.
1116 *
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).
1119 *
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);
1132 }
1134 template <class T>
1135 const T &as() const {
1136 JS_ASSERT(is<T>());
1137 return *static_cast<const T *>(this);
1138 }
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");
1157 }
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
1167 {
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()));
1171 }
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)
1180 {
1181 return &lhs == &rhs;
1182 }
1184 static MOZ_ALWAYS_INLINE bool
1185 operator!=(const JSObject &lhs, const JSObject &rhs)
1186 {
1187 return &lhs != &rhs;
1188 }
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)
1198 {
1199 return v.isObject() && v.toObject().isCallable();
1200 }
1202 inline JSObject *
1203 GetInnerObject(JSContext *cx, js::HandleObject obj)
1204 {
1205 if (JSObjectOp op = obj->getClass()->ext.innerObject)
1206 return op(cx, obj);
1207 return obj;
1208 }
1210 inline JSObject *
1211 GetOuterObject(JSContext *cx, js::HandleObject obj)
1212 {
1213 if (JSObjectOp op = obj->getClass()->ext.outerObject)
1214 return op(cx, obj);
1215 return obj;
1216 }
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)
1343 {
1344 if (clasp->finalize || newKind != GenericObject)
1345 return gc::TenuredHeap;
1346 return gc::DefaultHeap;
1347 }
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.
1382 *
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.
1416 *
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);
1424 }
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)
1450 {
1451 return GetPropertyPure(cx, obj, NameToId(name), vp);
1452 }
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)
1473 {
1474 return HasDataProperty(cx, obj, NameToId(name), vp);
1475 }
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)
1507 {
1508 if (vp.isObject())
1509 return &vp.toObject();
1510 return ToObjectSlow(cx, vp, false);
1511 }
1513 /* For converting stack values to objects. */
1514 MOZ_ALWAYS_INLINE JSObject *
1515 ToObjectFromStack(JSContext *cx, HandleValue vp)
1516 {
1517 if (vp.isObject())
1518 return &vp.toObject();
1519 return ToObjectSlow(cx, vp, true);
1520 }
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 */