LCOV - code coverage report
Current view: top level - js/src - jsobj.h (source / functions) Hit Total Coverage
Test: output.info Lines: 175 191 91.6 %
Date: 2017-07-14 16:53:18 Functions: 169 284 59.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13