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/. */
6 
7 #ifndef jsobj_h
8 #define jsobj_h
9 
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  */
18 
19 #include "mozilla/MemoryReporting.h"
20 
21 #include "gc/Barrier.h"
22 #include "gc/Marking.h"
23 #include "js/Conversions.h"
24 #include "js/GCAPI.h"
25 #include "js/HeapAPI.h"
26 #include "js/TraceableVector.h"
27 #include "vm/Shape.h"
28 #include "vm/String.h"
29 #include "vm/Xdr.h"
30 
31 namespace JS {
32 struct ClassInfo;
33 } // namespace JS
34 
35 namespace js {
36 
37 using PropertyDescriptorVector = TraceableVector<PropertyDescriptor>;
38 class GCMarker;
39 class Nursery;
40 
41 namespace gc {
42 class RelocationOverlay;
43 } // namespace gc
44 
45 inline JSObject*
CastAsObject(GetterOp op)46 CastAsObject(GetterOp op)
47 {
48     return JS_FUNC_TO_DATA_PTR(JSObject*, op);
49 }
50 
51 inline JSObject*
CastAsObject(SetterOp op)52 CastAsObject(SetterOp op)
53 {
54     return JS_FUNC_TO_DATA_PTR(JSObject*, op);
55 }
56 
57 inline Value
CastAsObjectJsval(GetterOp op)58 CastAsObjectJsval(GetterOp op)
59 {
60     return ObjectOrNullValue(CastAsObject(op));
61 }
62 
63 inline Value
CastAsObjectJsval(SetterOp op)64 CastAsObjectJsval(SetterOp op)
65 {
66     return ObjectOrNullValue(CastAsObject(op));
67 }
68 
69 /******************************************************************************/
70 
71 extern const Class IntlClass;
72 extern const Class JSONClass;
73 extern const Class MathClass;
74 
75 class GlobalObject;
76 class NewObjectCache;
77 
78 // Forward declarations, required for later friend declarations.
79 bool PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
80 bool SetImmutablePrototype(js::ExclusiveContext* cx, JS::HandleObject obj, bool* succeeded);
81 
82 }  /* namespace js */
83 
84 /*
85  * A JavaScript object. The members common to all objects are as follows:
86  *
87  * - The |group_| member stores the group of the object, which contains its
88  *   prototype object, its class and the possible types of its properties.
89  *
90  * Subclasses of JSObject --- mainly NativeObject and JSFunction --- add more
91  * members. Notable among these is the object's shape, which stores flags and
92  * some other state, and, for native objects, the layout of all its properties.
93  * The second word of a JSObject generally stores its shape; if the second word
94  * stores anything else, the value stored cannot be a valid Shape* pointer, so
95  * that shape guards can be performed on objects without regard to the specific
96  * layout in use.
97  */
98 class JSObject : public js::gc::Cell
99 {
100   protected:
101     js::HeapPtrObjectGroup group_;
102 
103   private:
104     friend class js::Shape;
105     friend class js::GCMarker;
106     friend class js::NewObjectCache;
107     friend class js::Nursery;
108     friend class js::gc::RelocationOverlay;
109     friend bool js::PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
110     friend bool js::SetImmutablePrototype(js::ExclusiveContext* cx, JS::HandleObject obj,
111                                           bool* succeeded);
112 
113     // Make a new group to use for a singleton object.
114     static js::ObjectGroup* makeLazyGroup(JSContext* cx, js::HandleObject obj);
115 
116   public:
isNative()117     bool isNative() const {
118         return getClass()->isNative();
119     }
120 
getClass()121     const js::Class* getClass() const {
122         return group_->clasp();
123     }
getJSClass()124     const JSClass* getJSClass() const {
125         return Jsvalify(getClass());
126     }
hasClass(const js::Class * c)127     bool hasClass(const js::Class* c) const {
128         return getClass() == c;
129     }
getOps()130     const js::ObjectOps* getOps() const {
131         return &getClass()->ops;
132     }
133 
group()134     js::ObjectGroup* group() const {
135         MOZ_ASSERT(!hasLazyGroup());
136         return groupRaw();
137     }
138 
groupRaw()139     js::ObjectGroup* groupRaw() const {
140         return group_;
141     }
142 
143     /*
144      * Whether this is the only object which has its specified group. This
145      * object will have its group constructed lazily as needed by analysis.
146      */
isSingleton()147     bool isSingleton() const {
148         return group_->singleton();
149     }
150 
151     /*
152      * Whether the object's group has not been constructed yet. If an object
153      * might have a lazy group, use getGroup() below, otherwise group().
154      */
hasLazyGroup()155     bool hasLazyGroup() const {
156         return group_->lazy();
157     }
158 
compartment()159     JSCompartment* compartment() const { return group_->compartment(); }
maybeCompartment()160     JSCompartment* maybeCompartment() const { return compartment(); }
161 
162     inline js::Shape* maybeShape() const;
163     inline js::Shape* ensureShape(js::ExclusiveContext* cx);
164 
165     /*
166      * Make a non-array object with the specified initial state. This method
167      * takes ownership of any extantSlots it is passed.
168      */
169     static inline JSObject* create(js::ExclusiveContext* cx,
170                                    js::gc::AllocKind kind,
171                                    js::gc::InitialHeap heap,
172                                    js::HandleShape shape,
173                                    js::HandleObjectGroup group);
174 
175     // Set the shape of an object. This pointer is valid for native objects and
176     // some non-native objects. After creating an object, the objects for which
177     // the shape pointer is invalid need to overwrite this pointer before a GC
178     // can occur.
179     inline void setInitialShapeMaybeNonNative(js::Shape* shape);
180     inline void setShapeMaybeNonNative(js::Shape* shape);
181 
182     // Set the initial slots and elements of an object. These pointers are only
183     // valid for native objects, but during initialization are set for all
184     // objects. For non-native objects, these must not be dynamically allocated
185     // pointers which leak when the non-native object finishes initialization.
186     inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
187     inline void setInitialElementsMaybeNonNative(js::HeapSlot* elements);
188 
189     enum GenerateShape {
190         GENERATE_NONE,
191         GENERATE_SHAPE
192     };
193 
194     bool setFlags(js::ExclusiveContext* cx, js::BaseShape::Flag flags,
195                   GenerateShape generateShape = GENERATE_NONE);
196     inline bool hasAllFlags(js::BaseShape::Flag flags) const;
197 
198     /*
199      * An object is a delegate if it is on another object's prototype or scope
200      * chain, and therefore the delegate might be asked implicitly to get or
201      * set a property on behalf of another object. Delegates may be accessed
202      * directly too, as may any object, but only those objects linked after the
203      * head of any prototype or scope chain are flagged as delegates. This
204      * definition helps to optimize shape-based property cache invalidation
205      * (see Purge{Scope,Proto}Chain in jsobj.cpp).
206      */
207     inline bool isDelegate() const;
setDelegate(js::ExclusiveContext * cx)208     bool setDelegate(js::ExclusiveContext* cx) {
209         return setFlags(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
210     }
211 
212     inline bool isBoundFunction() const;
213     inline bool hasSpecialEquality() const;
214 
215     inline bool watched() const;
setWatched(js::ExclusiveContext * cx)216     bool setWatched(js::ExclusiveContext* cx) {
217         return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
218     }
219 
220     // A "qualified" varobj is the object on which "qualified" variable
221     // declarations (i.e., those defined with "var") are kept.
222     //
223     // Conceptually, when a var binding is defined, it is defined on the
224     // innermost qualified varobj on the scope chain.
225     //
226     // Function scopes (CallObjects) are qualified varobjs, and there can be
227     // no other qualified varobj that is more inner for var bindings in that
228     // function. As such, all references to local var bindings in a function
229     // may be statically bound to the function scope. This is subject to
230     // further optimization. Unaliased bindings inside functions reside
231     // entirely on the frame, not in CallObjects.
232     //
233     // Global scopes are also qualified varobjs. It is possible to statically
234     // know, for a given script, that are no more inner qualified varobjs, so
235     // free variable references can be statically bound to the global.
236     //
237     // Finally, there are non-syntactic qualified varobjs used by embedders
238     // (e.g., Gecko and XPConnect), as they often wish to run scripts under a
239     // scope that captures var bindings.
240     inline bool isQualifiedVarObj() const;
setQualifiedVarObj(js::ExclusiveContext * cx)241     bool setQualifiedVarObj(js::ExclusiveContext* cx) {
242         return setFlags(cx, js::BaseShape::QUALIFIED_VAROBJ);
243     }
244 
245     // An "unqualified" varobj is the object on which "unqualified"
246     // assignments (i.e., bareword assignments for which the LHS does not
247     // exist on the scope chain) are kept.
248     inline bool isUnqualifiedVarObj() const;
249 
250     /*
251      * Objects with an uncacheable proto can have their prototype mutated
252      * without inducing a shape change on the object. Property cache entries
253      * and JIT inline caches should not be filled for lookups across prototype
254      * lookups on the object.
255      */
256     inline bool hasUncacheableProto() const;
setUncacheableProto(js::ExclusiveContext * cx)257     bool setUncacheableProto(js::ExclusiveContext* cx) {
258         return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
259     }
260 
261     /*
262      * Whether SETLELEM was used to access this object. See also the comment near
263      * PropertyTree::MAX_HEIGHT.
264      */
265     inline bool hadElementsAccess() const;
setHadElementsAccess(js::ExclusiveContext * cx)266     bool setHadElementsAccess(js::ExclusiveContext* cx) {
267         return setFlags(cx, js::BaseShape::HAD_ELEMENTS_ACCESS);
268     }
269 
270     /*
271      * Whether there may be indexed properties on this object, excluding any in
272      * the object's elements.
273      */
274     inline bool isIndexed() const;
275 
276     /*
277      * If this object was instantiated with `new Ctor`, return the constructor's
278      * display atom. Otherwise, return nullptr.
279      */
280     bool constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name);
281 
282     /*
283      * The same as constructorDisplayAtom above, however if this object has a
284      * lazy group, nullptr is returned. This allows for use in situations that
285      * cannot GC and where having some information, even if it is inconsistently
286      * available, is better than no information.
287      */
288     JSAtom* maybeConstructorDisplayAtom() const;
289 
290     /* GC support. */
291 
292     void traceChildren(JSTracer* trc);
293 
294     void fixupAfterMovingGC();
295 
rootKind()296     static js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; }
297     static const size_t MaxTagBits = 3;
isNullLike(const JSObject * obj)298     static bool isNullLike(const JSObject* obj) { return uintptr_t(obj) < (1 << MaxTagBits); }
299 
zone()300     MOZ_ALWAYS_INLINE JS::Zone* zone() const {
301         return group_->zone();
302     }
shadowZone()303     MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZone() const {
304         return JS::shadow::Zone::asShadowZone(zone());
305     }
zoneFromAnyThread()306     MOZ_ALWAYS_INLINE JS::Zone* zoneFromAnyThread() const {
307         return group_->zoneFromAnyThread();
308     }
shadowZoneFromAnyThread()309     MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZoneFromAnyThread() const {
310         return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
311     }
312     static MOZ_ALWAYS_INLINE void readBarrier(JSObject* obj);
313     static MOZ_ALWAYS_INLINE void writeBarrierPre(JSObject* obj);
314     static MOZ_ALWAYS_INLINE void writeBarrierPost(void* cellp, JSObject* prev, JSObject* next);
315 
316     /* Return the allocKind we would use if we were to tenure this object. */
317     js::gc::AllocKind allocKindForTenure(const js::Nursery& nursery) const;
318 
tenuredSizeOfThis()319     size_t tenuredSizeOfThis() const {
320         MOZ_ASSERT(isTenured());
321         return js::gc::Arena::thingSize(asTenured().getAllocKind());
322     }
323 
324     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info);
325 
326     // We can only use addSizeOfExcludingThis on tenured objects: it assumes it
327     // can apply mallocSizeOf to bits and pieces of the object, whereas objects
328     // in the nursery may have those bits and pieces allocated in the nursery
329     // along with them, and are not each their own malloc blocks.
330     size_t sizeOfIncludingThisInNursery() const;
331 
332     // Marks this object as having a singleton group, and leave the group lazy.
333     // Constructs a new, unique shape for the object. This should only be
334     // called for an object that was just created.
335     static inline bool setSingleton(js::ExclusiveContext* cx, js::HandleObject obj);
336 
337     // Change an existing object to have a singleton group.
338     static bool changeToSingleton(JSContext* cx, js::HandleObject obj);
339 
340     inline js::ObjectGroup* getGroup(JSContext* cx);
341 
groupFromGC()342     const js::HeapPtrObjectGroup& groupFromGC() const {
343         /* Direct field access for use by GC. */
344         return group_;
345     }
346 
347     /*
348      * We allow the prototype of an object to be lazily computed if the object
349      * is a proxy. In the lazy case, we store (JSObject*)0x1 in the proto field
350      * of the object's group. We offer three ways of getting the prototype:
351      *
352      * 1. obj->getProto() returns the prototype, but asserts if obj is a proxy
353      *    with a relevant getPrototype() handler.
354      * 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to
355      *    check if the proto is an object, nullptr, or lazily computed.
356      * 3. js::GetPrototype(cx, obj, &proto) computes the proto of an object.
357      *    If obj is a proxy and the proto is lazy, this code may allocate or
358      *    GC in order to compute the proto. Currently, it will not run JS code.
359      */
360 
getTaggedProto()361     js::TaggedProto getTaggedProto() const {
362         return group_->proto();
363     }
364 
365     bool hasTenuredProto() const;
366 
367     bool uninlinedIsProxy() const;
368 
getProto()369     JSObject* getProto() const {
370         MOZ_ASSERT(!hasLazyPrototype());
371         return getTaggedProto().toObjectOrNull();
372     }
373 
374     // Normal objects and a subset of proxies have uninteresting [[Prototype]].
375     // For such objects the [[Prototype]] is just a value returned when needed
376     // for accesses, or modified in response to requests.  These objects store
377     // the [[Prototype]] directly within |obj->type_|.
378     //
379     // Proxies that don't have such a simple [[Prototype]] instead have a
380     // "lazy" [[Prototype]].  Accessing the [[Prototype]] of such an object
381     // requires going through the proxy handler {get,set}Prototype and
382     // setImmutablePrototype methods.  This is most commonly useful for proxies
383     // that are wrappers around other objects.  If the [[Prototype]] of the
384     // underlying object changes, the [[Prototype]] of the wrapper must also
385     // simultaneously change.  We implement this by having the handler methods
386     // simply delegate to the wrapped object, forwarding its response to the
387     // caller.
388     //
389     // This method returns true if this object has a non-simple [[Prototype]]
390     // as described above, or false otherwise.
hasLazyPrototype()391     bool hasLazyPrototype() const {
392         bool lazy = getTaggedProto().isLazy();
393         MOZ_ASSERT_IF(lazy, uninlinedIsProxy());
394         return lazy;
395     }
396 
397     // True iff this object's [[Prototype]] is immutable.  Must not be called
398     // on proxies with lazy [[Prototype]]!
399     inline bool nonLazyPrototypeIsImmutable() const;
400 
401     inline void setGroup(js::ObjectGroup* group);
402 
403     /*
404      * Mark an object that has been iterated over and is a singleton. We need
405      * to recover this information in the object's type information after it
406      * is purged on GC.
407      */
408     inline bool isIteratedSingleton() const;
setIteratedSingleton(js::ExclusiveContext * cx)409     bool setIteratedSingleton(js::ExclusiveContext* cx) {
410         return setFlags(cx, js::BaseShape::ITERATED_SINGLETON);
411     }
412 
413     /*
414      * Mark an object as requiring its default 'new' type to have unknown
415      * properties.
416      */
417     inline bool isNewGroupUnknown() const;
418     static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
419 
420     // Mark an object as having its 'new' script information cleared.
421     inline bool wasNewScriptCleared() const;
setNewScriptCleared(js::ExclusiveContext * cx)422     bool setNewScriptCleared(js::ExclusiveContext* cx) {
423         return setFlags(cx, js::BaseShape::NEW_SCRIPT_CLEARED);
424     }
425 
426     /* Set a new prototype for an object with a singleton type. */
427     bool splicePrototype(JSContext* cx, const js::Class* clasp, js::Handle<js::TaggedProto> proto);
428 
429     /*
430      * For bootstrapping, whether to splice a prototype for Function.prototype
431      * or the global object.
432      */
433     bool shouldSplicePrototype(JSContext* cx);
434 
435     /*
436      * Scope chains.
437      *
438      * The scope chain of an object is the link in the search path when a script
439      * does a name lookup on a scope object. For JS internal scope objects ---
440      * Call, DeclEnv, Block, and With --- the chain is stored in the first fixed
441      * slot of the object.  For other scope objects, the chain goes directly to
442      * the global.
443      *
444      * In code which is not marked hasNonSyntacticScope, scope chains can
445      * contain only syntactic scope objects (see IsSyntacticScope) with a global
446      * object at the root as the scope of the outermost non-function script. In
447      * hasNonSyntacticScope code, the scope of the outermost non-function
448      * script might not be a global object, and can have a mix of other objects
449      * above it before the global object is reached.
450      */
451 
452     /*
453      * Get the enclosing scope of an object. When called on non-scope object,
454      * this will just be the global (the name "enclosing scope" still applies
455      * in this situation because non-scope objects can be on the scope chain).
456      */
457     inline JSObject* enclosingScope();
458 
459     inline js::GlobalObject& global() const;
460     inline bool isOwnGlobal() const;
461 
462     /*
463      * ES5 meta-object properties and operations.
464      */
465 
466   public:
467     // Indicates whether a non-proxy is extensible.  Don't call on proxies!
468     // This method really shouldn't exist -- but there are a few internal
469     // places that want it (JITs and the like), and it'd be a pain to mark them
470     // all as friends.
471     inline bool nonProxyIsExtensible() const;
472 
473   public:
474     /*
475      * Iterator-specific getters and setters.
476      */
477 
478     static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
479 
480     /*
481      * Back to generic stuff.
482      */
483     bool isCallable() const;
484     bool isConstructor() const;
485     JSNative callHook() const;
486     JSNative constructHook() const;
487 
488     MOZ_ALWAYS_INLINE void finalize(js::FreeOp* fop);
489 
490   public:
491     static bool reportReadOnly(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
492     bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
493     bool reportNotExtensible(JSContext* cx, unsigned report = JSREPORT_ERROR);
494 
495     /*
496      * Get the property with the given id, then call it as a function with the
497      * given arguments, providing this object as |this|. If the property isn't
498      * callable a TypeError will be thrown. On success the value returned by
499      * the call is stored in *vp.
500      */
501     bool callMethod(JSContext* cx, js::HandleId id, unsigned argc, js::Value* argv,
502                     js::MutableHandleValue vp);
503 
504     static bool nonNativeSetProperty(JSContext* cx, js::HandleObject obj, js::HandleId id,
505                                      js::HandleValue v, js::HandleValue receiver,
506                                      JS::ObjectOpResult& result);
507     static bool nonNativeSetElement(JSContext* cx, js::HandleObject obj, uint32_t index,
508                                     js::HandleValue v, js::HandleValue receiver,
509                                     JS::ObjectOpResult& result);
510 
511     static bool swap(JSContext* cx, JS::HandleObject a, JS::HandleObject b);
512 
513   private:
514     void fixDictionaryShapeAfterSwap();
515 
516   public:
517     inline void initArrayClass();
518 
519     /*
520      * In addition to the generic object interface provided by JSObject,
521      * specific types of objects may provide additional operations. To access,
522      * these addition operations, callers should use the pattern:
523      *
524      *   if (obj.is<XObject>()) {
525      *     XObject& x = obj.as<XObject>();
526      *     x.foo();
527      *   }
528      *
529      * These XObject classes form a hierarchy. For example, for a cloned block
530      * object, the following predicates are true: is<ClonedBlockObject>,
531      * is<BlockObject>, is<NestedScopeObject> and is<ScopeObject>. Each of
532      * these has a respective class that derives and adds operations.
533      *
534      * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
535      * triplet (along with any class YObject that derives XObject).
536      *
537      * Note that X represents a low-level representation and does not query the
538      * [[Class]] property of object defined by the spec (for this, see
539      * js::GetBuiltinClass).
540      */
541 
542     template <class T>
is()543     inline bool is() const { return getClass() == &T::class_; }
544 
545     template <class T>
as()546     T& as() {
547         MOZ_ASSERT(this->is<T>());
548         return *static_cast<T*>(this);
549     }
550 
551     template <class T>
as()552     const T& as() const {
553         MOZ_ASSERT(this->is<T>());
554         return *static_cast<const T*>(this);
555     }
556 
557 #ifdef DEBUG
558     void dump();
559 #endif
560 
561     /* JIT Accessors */
562 
offsetOfGroup()563     static size_t offsetOfGroup() { return offsetof(JSObject, group_); }
offsetOfShape()564     static size_t offsetOfShape() { return sizeof(JSObject); }
565 
566     // Maximum size in bytes of a JSObject.
567     static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
568 
569   private:
570     JSObject() = delete;
571     JSObject(const JSObject& other) = delete;
572     void operator=(const JSObject& other) = delete;
573 };
574 
575 template <class U>
576 MOZ_ALWAYS_INLINE JS::Handle<U*>
as()577 js::RootedBase<JSObject*>::as() const
578 {
579     const JS::Rooted<JSObject*>& self = *static_cast<const JS::Rooted<JSObject*>*>(this);
580     MOZ_ASSERT(self->is<U>());
581     return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
582 }
583 
584 template <class U>
585 MOZ_ALWAYS_INLINE JS::Handle<U*>
as()586 js::HandleBase<JSObject*>::as() const
587 {
588     const JS::Handle<JSObject*>& self = *static_cast<const JS::Handle<JSObject*>*>(this);
589     MOZ_ASSERT(self->is<U>());
590     return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
591 }
592 
593 /*
594  * The only sensible way to compare JSObject with == is by identity. We use
595  * const& instead of * as a syntactic way to assert non-null. This leads to an
596  * abundance of address-of operators to identity. Hence this overload.
597  */
598 static MOZ_ALWAYS_INLINE bool
599 operator==(const JSObject& lhs, const JSObject& rhs)
600 {
601     return &lhs == &rhs;
602 }
603 
604 static MOZ_ALWAYS_INLINE bool
605 operator!=(const JSObject& lhs, const JSObject& rhs)
606 {
607     return &lhs != &rhs;
608 }
609 
610 // Size of the various GC thing allocation sizes used for objects.
611 struct JSObject_Slots0 : JSObject { void* data[3]; };
612 struct JSObject_Slots2 : JSObject { void* data[3]; js::Value fslots[2]; };
613 struct JSObject_Slots4 : JSObject { void* data[3]; js::Value fslots[4]; };
614 struct JSObject_Slots8 : JSObject { void* data[3]; js::Value fslots[8]; };
615 struct JSObject_Slots12 : JSObject { void* data[3]; js::Value fslots[12]; };
616 struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
617 
618 /* static */ MOZ_ALWAYS_INLINE void
readBarrier(JSObject * obj)619 JSObject::readBarrier(JSObject* obj)
620 {
621     MOZ_ASSERT_IF(obj, !isNullLike(obj));
622     if (obj && obj->isTenured())
623         obj->asTenured().readBarrier(&obj->asTenured());
624 }
625 
626 /* static */ MOZ_ALWAYS_INLINE void
writeBarrierPre(JSObject * obj)627 JSObject::writeBarrierPre(JSObject* obj)
628 {
629     MOZ_ASSERT_IF(obj, !isNullLike(obj));
630     if (obj && obj->isTenured())
631         obj->asTenured().writeBarrierPre(&obj->asTenured());
632 }
633 
634 /* static */ MOZ_ALWAYS_INLINE void
writeBarrierPost(void * cellp,JSObject * prev,JSObject * next)635 JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
636 {
637     MOZ_ASSERT(cellp);
638     MOZ_ASSERT_IF(next, !IsNullTaggedPointer(next));
639     MOZ_ASSERT_IF(prev, !IsNullTaggedPointer(prev));
640 
641     // If the target needs an entry, add it.
642     js::gc::StoreBuffer* buffer;
643     if (next && (buffer = next->storeBuffer())) {
644         // If we know that the prev has already inserted an entry, we can skip
645         // doing the lookup to add the new entry. Note that we cannot safely
646         // assert the presence of the entry because it may have been added
647         // via a different store buffer.
648         if (prev && prev->storeBuffer())
649             return;
650         buffer->putCell(static_cast<js::gc::Cell**>(cellp));
651         return;
652     }
653 
654     // Remove the prev entry if the new value does not need it.
655     if (prev && (buffer = prev->storeBuffer()))
656         buffer->unputCell(static_cast<js::gc::Cell**>(cellp));
657 }
658 
659 namespace js {
660 
661 inline bool
IsCallable(const Value & v)662 IsCallable(const Value& v)
663 {
664     return v.isObject() && v.toObject().isCallable();
665 }
666 
667 // ES6 rev 24 (2014 April 27) 7.2.5 IsConstructor
668 inline bool
IsConstructor(const Value & v)669 IsConstructor(const Value& v)
670 {
671     return v.isObject() && v.toObject().isConstructor();
672 }
673 
674 } /* namespace js */
675 
676 class JSValueArray {
677   public:
678     const js::Value* array;
679     size_t length;
680 
JSValueArray(const js::Value * v,size_t c)681     JSValueArray(const js::Value* v, size_t c) : array(v), length(c) {}
682 };
683 
684 class ValueArray {
685   public:
686     js::Value* array;
687     size_t length;
688 
ValueArray(js::Value * v,size_t c)689     ValueArray(js::Value* v, size_t c) : array(v), length(c) {}
690 };
691 
692 namespace js {
693 
694 /*** Standard internal methods ********************************************************************
695  *
696  * The functions below are the fundamental operations on objects. See the
697  * comment about "Standard internal methods" in jsapi.h.
698  */
699 
700 /*
701  * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
702  *
703  * If obj is definitely not a proxy, the infallible obj->getProto() can be used
704  * instead. See the comment on JSObject::getTaggedProto().
705  */
706 inline bool
707 GetPrototype(JSContext* cx, HandleObject obj, MutableHandleObject protop);
708 
709 /*
710  * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto.
711  *
712  * Returns false on error, success of operation in *result. For example, if
713  * obj is not extensible, its prototype is fixed. js::SetPrototype will return
714  * true, because no exception is thrown for this; but *result will be false.
715  */
716 extern bool
717 SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto,
718              ObjectOpResult& result);
719 
720 /* Convenience function: like the above, but throw on failure. */
721 extern bool
722 SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto);
723 
724 /*
725  * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
726  * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
727  * well.
728  */
729 inline bool
730 IsExtensible(ExclusiveContext* cx, HandleObject obj, bool* extensible);
731 
732 /*
733  * ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj|
734  * to false.  Indicate success or failure through the |result| outparam, or
735  * actual error through the return value.
736  */
737 extern bool
738 PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result);
739 
740 /* Convenience function. As above, but throw on failure. */
741 extern bool
742 PreventExtensions(JSContext* cx, HandleObject obj);
743 
744 /*
745  * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties.
746  *
747  * If no such property exists on obj, return true with desc.object() set to
748  * null.
749  */
750 extern bool
751 GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
752                          MutableHandle<PropertyDescriptor> desc);
753 
754 /* ES6 [[DefineOwnProperty]]. Define a property on obj. */
755 extern bool
756 DefineProperty(JSContext* cx, HandleObject obj, HandleId id,
757                Handle<PropertyDescriptor> desc, ObjectOpResult& result);
758 
759 extern bool
760 DefineProperty(ExclusiveContext* cx, HandleObject obj, HandleId id, HandleValue value,
761                JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
762 
763 extern bool
764 DefineProperty(ExclusiveContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
765                JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
766 
767 extern bool
768 DefineElement(ExclusiveContext* cx, HandleObject obj, uint32_t index, HandleValue value,
769               JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
770 
771 /*
772  * When the 'result' out-param is omitted, the behavior is the same as above, except
773  * that any failure results in a TypeError.
774  */
775 extern bool
776 DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc);
777 
778 extern bool
779 DefineProperty(ExclusiveContext* cx, HandleObject obj, HandleId id, HandleValue value,
780                JSGetterOp getter = nullptr,
781                JSSetterOp setter = nullptr,
782                unsigned attrs = JSPROP_ENUMERATE);
783 
784 extern bool
785 DefineProperty(ExclusiveContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
786                JSGetterOp getter = nullptr,
787                JSSetterOp setter = nullptr,
788                unsigned attrs = JSPROP_ENUMERATE);
789 
790 extern bool
791 DefineElement(ExclusiveContext* cx, HandleObject obj, uint32_t index, HandleValue value,
792               JSGetterOp getter = nullptr,
793               JSSetterOp setter = nullptr,
794               unsigned attrs = JSPROP_ENUMERATE);
795 
796 /*
797  * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own
798  * or inherited property obj[id]), false otherwise.
799  */
800 inline bool
801 HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
802 
803 inline bool
804 HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* foundp);
805 
806 /*
807  * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
808  * such property exists.
809  *
810  * Typically obj == receiver; if obj != receiver then the caller is most likely
811  * a proxy using GetProperty to finish a property get that started out as
812  * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
813  */
814 inline bool
815 GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
816             MutableHandleValue vp);
817 
818 inline bool
GetProperty(JSContext * cx,HandleObject obj,HandleValue receiver,PropertyName * name,MutableHandleValue vp)819 GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, PropertyName* name,
820             MutableHandleValue vp)
821 {
822     RootedId id(cx, NameToId(name));
823     return GetProperty(cx, obj, receiver, id, vp);
824 }
825 
826 inline bool
GetProperty(JSContext * cx,HandleObject obj,HandleObject receiver,HandleId id,MutableHandleValue vp)827 GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
828             MutableHandleValue vp)
829 {
830     RootedValue receiverValue(cx, ObjectValue(*receiver));
831     return GetProperty(cx, obj, receiverValue, id, vp);
832 }
833 
834 inline bool
GetProperty(JSContext * cx,HandleObject obj,HandleObject receiver,PropertyName * name,MutableHandleValue vp)835 GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
836             MutableHandleValue vp)
837 {
838     RootedValue receiverValue(cx, ObjectValue(*receiver));
839     return GetProperty(cx, obj, receiverValue, name, vp);
840 }
841 
842 inline bool
843 GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
844            MutableHandleValue vp);
845 
846 inline bool
847 GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
848            MutableHandleValue vp);
849 
850 inline bool
851 GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
852 
853 inline bool
GetPropertyNoGC(JSContext * cx,JSObject * obj,JSObject * receiver,jsid id,Value * vp)854 GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
855 {
856     return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), id, vp);
857 }
858 
859 inline bool
GetPropertyNoGC(JSContext * cx,JSObject * obj,const Value & receiver,PropertyName * name,Value * vp)860 GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
861 {
862     return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
863 }
864 
865 inline bool
GetPropertyNoGC(JSContext * cx,JSObject * obj,JSObject * receiver,PropertyName * name,Value * vp)866 GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, PropertyName* name, Value* vp)
867 {
868     return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), name, vp);
869 }
870 
871 inline bool
872 GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
873 
874 inline bool
875 GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);
876 
877 /*
878  * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
879  *
880  * The `receiver` argument has to do with how [[Set]] interacts with the
881  * prototype chain and proxies. It's hard to explain and ES6 doesn't really
882  * try. Long story short, if you just want bog-standard assignment, pass
883  * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
884  * doesn't have a receiver parameter.
885  *
886  * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
887  * proxy's target, and the proxy is using SetProperty to finish an assignment
888  * that started out as `receiver[id] = v`, by delegating it to obj.
889  */
890 inline bool
891 SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
892             HandleValue receiver, ObjectOpResult& result);
893 
894 inline bool
SetProperty(JSContext * cx,HandleObject obj,HandleId id,HandleValue v)895 SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
896 {
897     RootedValue receiver(cx, ObjectValue(*obj));
898     ObjectOpResult result;
899     return SetProperty(cx, obj, id, v, receiver, result) &&
900            result.checkStrict(cx, obj, id);
901 }
902 
903 inline bool
SetProperty(JSContext * cx,HandleObject obj,PropertyName * name,HandleValue v,HandleValue receiver,ObjectOpResult & result)904 SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v,
905             HandleValue receiver, ObjectOpResult& result)
906 {
907     RootedId id(cx, NameToId(name));
908     return SetProperty(cx, obj, id, v, receiver, result);
909 }
910 
911 inline bool
SetProperty(JSContext * cx,HandleObject obj,PropertyName * name,HandleValue v)912 SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v)
913 {
914     RootedId id(cx, NameToId(name));
915     RootedValue receiver(cx, ObjectValue(*obj));
916     ObjectOpResult result;
917     return SetProperty(cx, obj, id, v, receiver, result) &&
918            result.checkStrict(cx, obj, id);
919 }
920 
921 inline bool
922 SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
923            HandleValue receiver, ObjectOpResult& result);
924 
925 /*
926  * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
927  * success, the spec says this is supposed to return a boolean value, which we
928  * don't bother doing.
929  */
930 inline bool
PutProperty(JSContext * cx,HandleObject obj,HandleId id,HandleValue v,bool strict)931 PutProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, bool strict)
932 {
933     RootedValue receiver(cx, ObjectValue(*obj));
934     ObjectOpResult result;
935     return SetProperty(cx, obj, id, v, receiver, result) &&
936            result.checkStrictErrorOrWarning(cx, obj, id, strict);
937 }
938 
939 /*
940  * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
941  */
942 inline bool
943 DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result);
944 
945 inline bool
946 DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result);
947 
948 
949 /*** SpiderMonkey nonstandard internal methods ***************************************************/
950 
951 /*
952  * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently
953  * trying to change it will not work.  If an internal error occurred,
954  * returns false.  Otherwise, |*succeeded| is set to true iff |obj|'s
955  * [[Prototype]] is now immutable.
956  */
957 extern bool
958 SetImmutablePrototype(js::ExclusiveContext* cx, JS::HandleObject obj, bool* succeeded);
959 
960 extern bool
961 GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
962                       MutableHandle<PropertyDescriptor> desc);
963 
964 /*
965  * Deprecated. A version of HasProperty that also returns the object on which
966  * the property was found (but that information is unreliable for proxies), and
967  * the Shape of the property, if native.
968  */
969 extern bool
970 LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
971                MutableHandleObject objp, MutableHandleShape propp);
972 
973 inline bool
LookupProperty(JSContext * cx,HandleObject obj,PropertyName * name,MutableHandleObject objp,MutableHandleShape propp)974 LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
975                MutableHandleObject objp, MutableHandleShape propp)
976 {
977     RootedId id(cx, NameToId(name));
978     return LookupProperty(cx, obj, id, objp, propp);
979 }
980 
981 /* Set *result to tell whether obj has an own property with the given id. */
982 extern bool
983 HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result);
984 
985 /*
986  * Set a watchpoint: a synchronous callback when the given property of the
987  * given object is set.
988  *
989  * Watchpoints are nonstandard and do not fit in well with the way ES6
990  * specifies [[Set]]. They are also insufficient for implementing
991  * Object.observe.
992  */
993 extern bool
994 WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
995 
996 /* Clear a watchpoint. */
997 extern bool
998 UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id);
999 
1000 /* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
1001 extern bool
1002 ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
1003 
1004 inline bool
ToPrimitive(JSContext * cx,MutableHandleValue vp)1005 ToPrimitive(JSContext* cx, MutableHandleValue vp)
1006 {
1007     if (vp.isPrimitive())
1008         return true;
1009     return ToPrimitiveSlow(cx, JSTYPE_VOID, vp);
1010 }
1011 
1012 inline bool
ToPrimitive(JSContext * cx,JSType preferredType,MutableHandleValue vp)1013 ToPrimitive(JSContext* cx, JSType preferredType, MutableHandleValue vp)
1014 {
1015     if (vp.isPrimitive())
1016         return true;
1017     return ToPrimitiveSlow(cx, preferredType, vp);
1018 }
1019 
1020 /*
1021  * toString support. (This isn't called GetClassName because there's a macro in
1022  * <windows.h> with that name.)
1023  */
1024 extern const char*
1025 GetObjectClassName(JSContext* cx, HandleObject obj);
1026 
1027 /*
1028  * Return an object that may be used as `this` in place of obj. For most
1029  * objects this just returns obj.
1030  *
1031  * Some JSObjects shouldn't be exposed directly to script. This includes (at
1032  * least) DynamicWithObjects and Window objects. However, since both of those
1033  * can be on scope chains, we sometimes would expose those as `this` if we
1034  * were not so vigilant about calling GetThisValue where appropriate.
1035  *
1036  * See comments at ComputeImplicitThis.
1037  */
1038 Value
1039 GetThisValue(JSObject* obj);
1040 
1041 /* * */
1042 
1043 typedef JSObject* (*ClassInitializerOp)(JSContext* cx, JS::HandleObject obj);
1044 
1045 /* Fast access to builtin constructors and prototypes. */
1046 bool
1047 GetBuiltinConstructor(ExclusiveContext* cx, JSProtoKey key, MutableHandleObject objp);
1048 
1049 bool
1050 GetBuiltinPrototype(ExclusiveContext* cx, JSProtoKey key, MutableHandleObject objp);
1051 
1052 JSObject*
1053 GetBuiltinPrototypePure(GlobalObject* global, JSProtoKey protoKey);
1054 
1055 extern bool
1056 SetClassAndProto(JSContext* cx, HandleObject obj,
1057                  const Class* clasp, Handle<TaggedProto> proto);
1058 
1059 extern bool
1060 IsStandardPrototype(JSObject* obj, JSProtoKey key);
1061 
1062 } /* namespace js */
1063 
1064 /*
1065  * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
1066  */
1067 extern const char js_watch_str[];
1068 extern const char js_unwatch_str[];
1069 extern const char js_hasOwnProperty_str[];
1070 extern const char js_isPrototypeOf_str[];
1071 extern const char js_propertyIsEnumerable_str[];
1072 
1073 #ifdef JS_OLD_GETTER_SETTER_METHODS
1074 extern const char js_defineGetter_str[];
1075 extern const char js_defineSetter_str[];
1076 extern const char js_lookupGetter_str[];
1077 extern const char js_lookupSetter_str[];
1078 #endif
1079 
1080 namespace js {
1081 
1082 inline gc::InitialHeap
GetInitialHeap(NewObjectKind newKind,const Class * clasp)1083 GetInitialHeap(NewObjectKind newKind, const Class* clasp)
1084 {
1085     if (newKind != GenericObject)
1086         return gc::TenuredHeap;
1087     if (clasp->finalize && !(clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE))
1088         return gc::TenuredHeap;
1089     return gc::DefaultHeap;
1090 }
1091 
1092 bool
1093 NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
1094                                    NewObjectKind newKind, const Class* clasp);
1095 
1096 // ES6 9.1.15 GetPrototypeFromConstructor.
1097 extern bool
1098 GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto);
1099 
1100 extern bool
1101 GetPrototypeFromCallableConstructor(JSContext* cx, const CallArgs& args, js::MutableHandleObject proto);
1102 
1103 // Specialized call for constructing |this| with a known function callee,
1104 // and a known prototype.
1105 extern JSObject*
1106 CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
1107                                HandleObject proto, NewObjectKind newKind = GenericObject);
1108 
1109 // Specialized call for constructing |this| with a known function callee.
1110 extern JSObject*
1111 CreateThisForFunction(JSContext* cx, js::HandleObject callee, js::HandleObject newTarget,
1112                       NewObjectKind newKind);
1113 
1114 // Generic call for constructing |this|.
1115 extern JSObject*
1116 CreateThis(JSContext* cx, const js::Class* clasp, js::HandleObject callee);
1117 
1118 extern JSObject*
1119 CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> proto);
1120 
1121 extern JSObject*
1122 DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKind = GenericObject);
1123 
1124 extern bool
1125 DefineProperties(JSContext* cx, HandleObject obj, HandleObject props);
1126 
1127 inline JSGetterOp
CastAsGetterOp(JSObject * object)1128 CastAsGetterOp(JSObject* object)
1129 {
1130     return JS_DATA_TO_FUNC_PTR(JSGetterOp, object);
1131 }
1132 
1133 inline JSSetterOp
CastAsSetterOp(JSObject * object)1134 CastAsSetterOp(JSObject* object)
1135 {
1136     return JS_DATA_TO_FUNC_PTR(JSSetterOp, object);
1137 }
1138 
1139 /* ES6 draft rev 32 (2015 Feb 2) 6.2.4.5 ToPropertyDescriptor(Obj) */
1140 bool
1141 ToPropertyDescriptor(JSContext* cx, HandleValue descval, bool checkAccessors,
1142                      MutableHandle<PropertyDescriptor> desc);
1143 
1144 /*
1145  * Throw a TypeError if desc.getterObject() or setterObject() is not
1146  * callable. This performs exactly the checks omitted by ToPropertyDescriptor
1147  * when checkAccessors is false.
1148  */
1149 bool
1150 CheckPropertyDescriptorAccessors(JSContext* cx, Handle<PropertyDescriptor> desc);
1151 
1152 void
1153 CompletePropertyDescriptor(MutableHandle<PropertyDescriptor> desc);
1154 
1155 /*
1156  * Read property descriptors from props, as for Object.defineProperties. See
1157  * ES5 15.2.3.7 steps 3-5.
1158  */
1159 extern bool
1160 ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors,
1161                         AutoIdVector* ids, MutableHandle<PropertyDescriptorVector> descs);
1162 
1163 /* Read the name using a dynamic lookup on the scopeChain. */
1164 extern bool
1165 LookupName(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1166            MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
1167 
1168 extern bool
1169 LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* scopeChain,
1170                JSObject** objp, JSObject** pobjp, Shape** propp);
1171 
1172 /*
1173  * Like LookupName except returns the global object if 'name' is not found in
1174  * any preceding scope.
1175  *
1176  * Additionally, pobjp and propp are not needed by callers so they are not
1177  * returned.
1178  */
1179 extern bool
1180 LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1181                             MutableHandleObject objp);
1182 
1183 /*
1184  * Like LookupName except returns the unqualified var object if 'name' is not
1185  * found in any preceding scope. Normally the unqualified var object is the
1186  * global. If the value for the name in the looked-up scope is an
1187  * uninitialized lexical, an UninitializedLexicalObject is returned.
1188  *
1189  * Additionally, pobjp is not needed by callers so it is not returned.
1190  */
1191 extern bool
1192 LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1193                       MutableHandleObject objp);
1194 
1195 } // namespace js
1196 
1197 namespace js {
1198 
1199 extern JSObject*
1200 FindVariableScope(JSContext* cx, JSFunction** funp);
1201 
1202 bool
1203 LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp,
1204                    Shape** propp);
1205 
1206 bool
1207 GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp);
1208 
1209 bool
1210 GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
1211                          MutableHandle<PropertyDescriptor> desc);
1212 
1213 bool
1214 GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
1215 
1216 /*
1217  * ES6 draft rev 32 (2015 Feb 2) 6.2.4.4 FromPropertyDescriptor(Desc).
1218  *
1219  * If desc.object() is null, then vp is set to undefined.
1220  */
1221 extern bool
1222 FromPropertyDescriptor(JSContext* cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
1223 
1224 /*
1225  * Like FromPropertyDescriptor, but ignore desc.object() and always set vp
1226  * to an object on success.
1227  *
1228  * Use FromPropertyDescriptor for getOwnPropertyDescriptor, since desc.object()
1229  * is used to indicate whether a result was found or not.  Use this instead for
1230  * defineProperty: it would be senseless to define a "missing" property.
1231  */
1232 extern bool
1233 FromPropertyDescriptorToObject(JSContext* cx, Handle<PropertyDescriptor> desc,
1234                                MutableHandleValue vp);
1235 
1236 extern bool
1237 IsDelegate(JSContext* cx, HandleObject obj, const Value& v, bool* result);
1238 
1239 // obj is a JSObject*, but we root it immediately up front. We do it
1240 // that way because we need a Rooted temporary in this method anyway.
1241 extern bool
1242 IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result);
1243 
1244 /* Wrap boolean, number or string as Boolean, Number or String object. */
1245 extern JSObject*
1246 PrimitiveToObject(JSContext* cx, const Value& v);
1247 
1248 } /* namespace js */
1249 
1250 namespace js {
1251 
1252 /* For converting stack values to objects. */
1253 MOZ_ALWAYS_INLINE JSObject*
ToObjectFromStack(JSContext * cx,HandleValue vp)1254 ToObjectFromStack(JSContext* cx, HandleValue vp)
1255 {
1256     if (vp.isObject())
1257         return &vp.toObject();
1258     return js::ToObjectSlow(cx, vp, true);
1259 }
1260 
1261 template<XDRMode mode>
1262 bool
1263 XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj);
1264 
1265 extern bool
1266 ReportGetterOnlyAssignment(JSContext* cx, bool strict);
1267 
1268 /*
1269  * Report a TypeError: "so-and-so is not an object".
1270  * Using NotNullObject is usually less code.
1271  */
1272 extern void
1273 ReportNotObject(JSContext* cx, const Value& v);
1274 
1275 inline JSObject*
NonNullObject(JSContext * cx,const Value & v)1276 NonNullObject(JSContext* cx, const Value& v)
1277 {
1278     if (v.isObject())
1279         return &v.toObject();
1280     ReportNotObject(cx, v);
1281     return nullptr;
1282 }
1283 
1284 extern const char*
1285 InformalValueTypeName(const Value& v);
1286 
1287 extern bool
1288 GetFirstArgumentAsObject(JSContext* cx, const CallArgs& args, const char* method,
1289                          MutableHandleObject objp);
1290 
1291 /* Helpers for throwing. These always return false. */
1292 extern bool
1293 Throw(JSContext* cx, jsid id, unsigned errorNumber);
1294 
1295 extern bool
1296 Throw(JSContext* cx, JSObject* obj, unsigned errorNumber);
1297 
1298 enum class IntegrityLevel {
1299     Sealed,
1300     Frozen
1301 };
1302 
1303 /*
1304  * ES6 rev 29 (6 Dec 2014) 7.3.13. Mark obj as non-extensible, and adjust each
1305  * of obj's own properties' attributes appropriately: each property becomes
1306  * non-configurable, and if level == Frozen, data properties become
1307  * non-writable as well.
1308  */
1309 extern bool
1310 SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level);
1311 
1312 inline bool
FreezeObject(JSContext * cx,HandleObject obj)1313 FreezeObject(JSContext* cx, HandleObject obj)
1314 {
1315     return SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
1316 }
1317 
1318 /*
1319  * ES6 rev 29 (6 Dec 2014) 7.3.14. Code shared by Object.isSealed and
1320  * Object.isFrozen.
1321  */
1322 extern bool
1323 TestIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level, bool* resultp);
1324 
1325 }  /* namespace js */
1326 
1327 #endif /* jsobj_h */
1328