LCOV - code coverage report
Current view: top level - js/src/vm - TypeInference.h (source / functions) Hit Total Coverage
Test: output.info Lines: 200 248 80.6 %
Date: 2017-07-14 16:53:18 Functions: 89 108 82.4 %
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             : /* Definitions related to javascript type inference. */
       8             : 
       9             : #ifndef vm_TypeInference_h
      10             : #define vm_TypeInference_h
      11             : 
      12             : #include "mozilla/MemoryReporting.h"
      13             : 
      14             : #include "jsalloc.h"
      15             : #include "jsfriendapi.h"
      16             : #include "jstypes.h"
      17             : 
      18             : #include "ds/IdValuePair.h"
      19             : #include "ds/LifoAlloc.h"
      20             : #include "gc/Barrier.h"
      21             : #include "gc/Marking.h"
      22             : #include "jit/IonTypes.h"
      23             : #include "js/UbiNode.h"
      24             : #include "js/Utility.h"
      25             : #include "js/Vector.h"
      26             : #include "threading/ProtectedData.h"
      27             : #include "vm/TaggedProto.h"
      28             : 
      29             : namespace js {
      30             : 
      31             : namespace jit {
      32             :     struct IonScript;
      33             :     class JitAllocPolicy;
      34             :     class TempAllocator;
      35             : } // namespace jit
      36             : 
      37             : class TypeConstraint;
      38             : class TypeNewScript;
      39             : class TypeZone;
      40             : class CompilerConstraintList;
      41             : class HeapTypeSetKey;
      42             : 
      43             : /*
      44             :  * Type inference memory management overview.
      45             :  *
      46             :  * Type information about the values observed within scripts and about the
      47             :  * contents of the heap is accumulated as the program executes. Compilation
      48             :  * accumulates constraints relating type information on the heap with the
      49             :  * compilations that should be invalidated when those types change. Type
      50             :  * information and constraints are allocated in the zone's typeLifoAlloc,
      51             :  * and on GC all data referring to live things is copied into a new allocator.
      52             :  * Thus, type set and constraints only hold weak references.
      53             :  */
      54             : 
      55             : /* Flags and other state stored in TypeSet::flags */
      56             : enum : uint32_t {
      57             :     TYPE_FLAG_UNDEFINED =   0x1,
      58             :     TYPE_FLAG_NULL      =   0x2,
      59             :     TYPE_FLAG_BOOLEAN   =   0x4,
      60             :     TYPE_FLAG_INT32     =   0x8,
      61             :     TYPE_FLAG_DOUBLE    =  0x10,
      62             :     TYPE_FLAG_STRING    =  0x20,
      63             :     TYPE_FLAG_SYMBOL    =  0x40,
      64             :     TYPE_FLAG_LAZYARGS  =  0x80,
      65             :     TYPE_FLAG_ANYOBJECT = 0x100,
      66             : 
      67             :     /* Mask containing all primitives */
      68             :     TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
      69             :                           TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
      70             :                           TYPE_FLAG_SYMBOL,
      71             : 
      72             :     /* Mask/shift for the number of objects in objectSet */
      73             :     TYPE_FLAG_OBJECT_COUNT_MASK     = 0x3e00,
      74             :     TYPE_FLAG_OBJECT_COUNT_SHIFT    = 9,
      75             :     TYPE_FLAG_OBJECT_COUNT_LIMIT    = 7,
      76             :     TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
      77             :         TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
      78             : 
      79             :     /* Whether the contents of this type set are totally unknown. */
      80             :     TYPE_FLAG_UNKNOWN             = 0x00004000,
      81             : 
      82             :     /* Mask of normal type flags on a type set. */
      83             :     TYPE_FLAG_BASE_MASK           = 0x000041ff,
      84             : 
      85             :     /* Additional flags for HeapTypeSet sets. */
      86             : 
      87             :     /*
      88             :      * Whether the property has ever been deleted or reconfigured to behave
      89             :      * differently from a plain data property, other than making the property
      90             :      * non-writable.
      91             :      */
      92             :     TYPE_FLAG_NON_DATA_PROPERTY = 0x00008000,
      93             : 
      94             :     /* Whether the property has ever been made non-writable. */
      95             :     TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
      96             : 
      97             :     /* Whether the property might not be constant. */
      98             :     TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
      99             : 
     100             :     /*
     101             :      * Whether the property is definitely in a particular slot on all objects
     102             :      * from which it has not been deleted or reconfigured. For singletons
     103             :      * this may be a fixed or dynamic slot, and for other objects this will be
     104             :      * a fixed slot.
     105             :      *
     106             :      * If the property is definite, mask and shift storing the slot + 1.
     107             :      * Otherwise these bits are clear.
     108             :      */
     109             :     TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
     110             :     TYPE_FLAG_DEFINITE_SHIFT      = 18
     111             : };
     112             : typedef uint32_t TypeFlags;
     113             : 
     114             : /* Flags and other state stored in ObjectGroup::Flags */
     115             : enum : uint32_t {
     116             :     /* Whether this group is associated with some allocation site. */
     117             :     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
     118             : 
     119             :     /* Whether this group is associated with a single object. */
     120             :     OBJECT_FLAG_SINGLETON             = 0x2,
     121             : 
     122             :     /*
     123             :      * Whether this group is used by objects whose singleton groups have not
     124             :      * been created yet.
     125             :      */
     126             :     OBJECT_FLAG_LAZY_SINGLETON        = 0x4,
     127             : 
     128             :     /* Mask/shift for the number of properties in propertySet */
     129             :     OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff8,
     130             :     OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 3,
     131             :     OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
     132             :         OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
     133             : 
     134             :     /* Whether any objects this represents may have sparse indexes. */
     135             :     OBJECT_FLAG_SPARSE_INDEXES        = 0x00010000,
     136             : 
     137             :     /* Whether any objects this represents may not have packed dense elements. */
     138             :     OBJECT_FLAG_NON_PACKED            = 0x00020000,
     139             : 
     140             :     /*
     141             :      * Whether any objects this represents may be arrays whose length does not
     142             :      * fit in an int32.
     143             :      */
     144             :     OBJECT_FLAG_LENGTH_OVERFLOW       = 0x00040000,
     145             : 
     146             :     /* Whether any objects have been iterated over. */
     147             :     OBJECT_FLAG_ITERATED              = 0x00080000,
     148             : 
     149             :     /* Whether any object this represents may have frozen elements. */
     150             :     OBJECT_FLAG_FROZEN_ELEMENTS       = 0x00100000,
     151             : 
     152             :     /*
     153             :      * For the function on a run-once script, whether the function has actually
     154             :      * run multiple times.
     155             :      */
     156             :     OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
     157             : 
     158             :     /*
     159             :      * For a global object, whether any array buffers in this compartment with
     160             :      * typed object views have ever been detached.
     161             :      */
     162             :     OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER = 0x00400000,
     163             : 
     164             :     /*
     165             :      * Whether objects with this type should be allocated directly in the
     166             :      * tenured heap.
     167             :      */
     168             :     OBJECT_FLAG_PRE_TENURE            = 0x00800000,
     169             : 
     170             :     /* Whether objects with this type might have copy on write elements. */
     171             :     OBJECT_FLAG_COPY_ON_WRITE         = 0x01000000,
     172             : 
     173             :     /* Whether this type has had its 'new' script cleared in the past. */
     174             :     OBJECT_FLAG_NEW_SCRIPT_CLEARED    = 0x02000000,
     175             : 
     176             :     /*
     177             :      * Whether all properties of this object are considered unknown.
     178             :      * If set, all other flags in DYNAMIC_MASK will also be set.
     179             :      */
     180             :     OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x04000000,
     181             : 
     182             :     /* Flags which indicate dynamic properties of represented objects. */
     183             :     OBJECT_FLAG_DYNAMIC_MASK          = 0x07ff0000,
     184             : 
     185             :     // Mask/shift for the kind of addendum attached to this group.
     186             :     OBJECT_FLAG_ADDENDUM_MASK         = 0x38000000,
     187             :     OBJECT_FLAG_ADDENDUM_SHIFT        = 27,
     188             : 
     189             :     // Mask/shift for this group's generation. If out of sync with the
     190             :     // TypeZone's generation, this group hasn't been swept yet.
     191             :     OBJECT_FLAG_GENERATION_MASK       = 0x40000000,
     192             :     OBJECT_FLAG_GENERATION_SHIFT      = 30,
     193             : };
     194             : typedef uint32_t ObjectGroupFlags;
     195             : 
     196             : class StackTypeSet;
     197             : class HeapTypeSet;
     198             : class TemporaryTypeSet;
     199             : 
     200             : /*
     201             :  * Information about the set of types associated with an lvalue. There are
     202             :  * three kinds of type sets:
     203             :  *
     204             :  * - StackTypeSet are associated with TypeScripts, for arguments and values
     205             :  *   observed at property reads. These are implicitly frozen on compilation
     206             :  *   and only have constraints added to them which can trigger invalidation of
     207             :  *   TypeNewScript information.
     208             :  *
     209             :  * - HeapTypeSet are associated with the properties of ObjectGroups. These
     210             :  *   may have constraints added to them to trigger invalidation of either
     211             :  *   compiled code or TypeNewScript information.
     212             :  *
     213             :  * - TemporaryTypeSet are created during compilation and do not outlive
     214             :  *   that compilation.
     215             :  *
     216             :  * The contents of a type set completely describe the values that a particular
     217             :  * lvalue might have, except for the following cases:
     218             :  *
     219             :  * - If an object's prototype or class is dynamically mutated, its group will
     220             :  *   change. Type sets containing the old group will not necessarily contain
     221             :  *   the new group. When this occurs, the properties of the old and new group
     222             :  *   will both be marked as unknown, which will prevent Ion from optimizing
     223             :  *   based on the object's type information.
     224             :  *
     225             :  * - If an unboxed object is converted to a native object, its group will also
     226             :  *   change and type sets containing the old group will not necessarily contain
     227             :  *   the new group. Unlike the above case, this will not degrade property type
     228             :  *   information, but Ion will no longer optimize unboxed objects with the old
     229             :  *   group.
     230             :  */
     231             : class TypeSet
     232             : {
     233             :   public:
     234             :     // Type set entry for either a JSObject with singleton type or a
     235             :     // non-singleton ObjectGroup.
     236             :     class ObjectKey {
     237             :       public:
     238           0 :         static intptr_t keyBits(ObjectKey* obj) { return (intptr_t) obj; }
     239       33019 :         static ObjectKey* getKey(ObjectKey* obj) { return obj; }
     240             : 
     241             :         static inline ObjectKey* get(JSObject* obj);
     242             :         static inline ObjectKey* get(ObjectGroup* group);
     243             : 
     244       47760 :         bool isGroup() {
     245       47760 :             return (uintptr_t(this) & 1) == 0;
     246             :         }
     247       26657 :         bool isSingleton() {
     248       26657 :             return (uintptr_t(this) & 1) != 0;
     249             :         }
     250             : 
     251             :         inline ObjectGroup* group();
     252             :         inline JSObject* singleton();
     253             : 
     254             :         inline ObjectGroup* groupNoBarrier();
     255             :         inline JSObject* singletonNoBarrier();
     256             : 
     257             :         const Class* clasp();
     258             :         TaggedProto proto();
     259             :         TypeNewScript* newScript();
     260             : 
     261             :         bool unknownProperties();
     262             :         bool hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
     263             :         bool hasStableClassAndProto(CompilerConstraintList* constraints);
     264             :         void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
     265             :         void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
     266             :         HeapTypeSetKey property(jsid id);
     267             :         void ensureTrackedProperty(JSContext* cx, jsid id);
     268             : 
     269             :         ObjectGroup* maybeGroup();
     270             : 
     271             :         JSCompartment* maybeCompartment();
     272             :     } JS_HAZ_GC_POINTER;
     273             : 
     274             :     // Information about a single concrete type. We pack this into one word,
     275             :     // where small values are particular primitive or other singleton types and
     276             :     // larger values are either specific JS objects or object groups.
     277             :     class Type
     278             :     {
     279             :         friend class TypeSet;
     280             : 
     281             :         uintptr_t data;
     282      203666 :         explicit Type(uintptr_t data) : data(data) {}
     283             : 
     284             :       public:
     285             : 
     286         927 :         uintptr_t raw() const { return data; }
     287             : 
     288      271746 :         bool isPrimitive() const {
     289      271746 :             return data < JSVAL_TYPE_OBJECT;
     290             :         }
     291             : 
     292          22 :         bool isPrimitive(JSValueType type) const {
     293          22 :             MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
     294          22 :             return (uintptr_t) type == data;
     295             :         }
     296             : 
     297      105280 :         JSValueType primitive() const {
     298      105280 :             MOZ_ASSERT(isPrimitive());
     299      105280 :             return (JSValueType) data;
     300             :         }
     301             : 
     302         152 :         bool isMagicArguments() const {
     303         152 :             return primitive() == JSVAL_TYPE_MAGIC;
     304             :         }
     305             : 
     306           0 :         bool isSomeObject() const {
     307           0 :             return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
     308             :         }
     309             : 
     310      182950 :         bool isAnyObject() const {
     311      182950 :             return data == JSVAL_TYPE_OBJECT;
     312             :         }
     313             : 
     314      288465 :         bool isUnknown() const {
     315      288465 :             return data == JSVAL_TYPE_UNKNOWN;
     316             :         }
     317             : 
     318             :         /* Accessors for types that are either JSObject or ObjectGroup. */
     319             : 
     320      121609 :         bool isObject() const {
     321      121609 :             MOZ_ASSERT(!isAnyObject() && !isUnknown());
     322      121610 :             return data > JSVAL_TYPE_UNKNOWN;
     323             :         }
     324             : 
     325      191112 :         bool isObjectUnchecked() const {
     326      191112 :             return data > JSVAL_TYPE_UNKNOWN;
     327             :         }
     328             : 
     329             :         inline ObjectKey* objectKey() const;
     330             : 
     331             :         /* Accessors for JSObject types */
     332             : 
     333       16126 :         bool isSingleton() const {
     334       16126 :             return isObject() && !!(data & 1);
     335             :         }
     336       88063 :         bool isSingletonUnchecked() const {
     337       88063 :             return isObjectUnchecked() && !!(data & 1);
     338             :         }
     339             : 
     340             :         inline JSObject* singleton() const;
     341             :         inline JSObject* singletonNoBarrier() const;
     342             : 
     343             :         /* Accessors for ObjectGroup types */
     344             : 
     345       14157 :         bool isGroup() const {
     346       14157 :             return isObject() && !(data & 1);
     347             :         }
     348       45532 :         bool isGroupUnchecked() const {
     349       45532 :             return isObjectUnchecked() && !(data & 1);
     350             :         }
     351             : 
     352             :         inline ObjectGroup* group() const;
     353             :         inline ObjectGroup* groupNoBarrier() const;
     354             : 
     355             :         inline void trace(JSTracer* trc);
     356             : 
     357             :         JSCompartment* maybeCompartment();
     358             : 
     359        5306 :         bool operator == (Type o) const { return data == o.data; }
     360        6840 :         bool operator != (Type o) const { return data != o.data; }
     361             :     } JS_HAZ_GC_POINTER;
     362             : 
     363        1616 :     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
     364        1543 :     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
     365         847 :     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
     366         984 :     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
     367        1566 :     static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
     368         856 :     static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
     369         178 :     static inline Type SymbolType()    { return Type(JSVAL_TYPE_SYMBOL); }
     370         197 :     static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
     371        2703 :     static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
     372        1314 :     static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
     373             : 
     374       85609 :     static inline Type PrimitiveType(JSValueType type) {
     375       85609 :         MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
     376       85609 :         return Type(type);
     377             :     }
     378             : 
     379             :     static inline Type ObjectType(JSObject* obj);
     380             :     static inline Type ObjectType(ObjectGroup* group);
     381             :     static inline Type ObjectType(ObjectKey* key);
     382             : 
     383             :     static const char* NonObjectTypeString(Type type);
     384             : 
     385             :     static const char* TypeString(Type type);
     386             :     static const char* ObjectGroupString(ObjectGroup* group);
     387             : 
     388             :   protected:
     389             :     /* Flags for this type set. */
     390             :     TypeFlags flags;
     391             : 
     392             :     /* Possible objects this type set can represent. */
     393             :     ObjectKey** objectSet;
     394             : 
     395             :   public:
     396             : 
     397       36885 :     TypeSet()
     398       36885 :       : flags(0), objectSet(nullptr)
     399       36885 :     {}
     400             : 
     401             :     void print(FILE* fp = stderr);
     402             : 
     403             :     /* Whether this set contains a specific type. */
     404             :     MOZ_ALWAYS_INLINE bool hasType(Type type) const;
     405             : 
     406       76942 :     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
     407      197216 :     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
     408      182618 :     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
     409       48006 :     bool empty() const { return !baseFlags() && !baseObjectCount(); }
     410             : 
     411         434 :     bool hasAnyFlag(TypeFlags flags) const {
     412         434 :         MOZ_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
     413         434 :         return !!(baseFlags() & flags);
     414             :     }
     415             : 
     416         197 :     bool nonDataProperty() const {
     417         197 :         return flags & TYPE_FLAG_NON_DATA_PROPERTY;
     418             :     }
     419         101 :     bool nonWritableProperty() const {
     420         101 :         return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
     421             :     }
     422       15306 :     bool nonConstantProperty() const {
     423       15306 :         return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
     424             :     }
     425        1221 :     bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
     426        1132 :     unsigned definiteSlot() const {
     427        1132 :         MOZ_ASSERT(definiteProperty());
     428        1132 :         return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
     429             :     }
     430             : 
     431             :     /* Join two type sets into a new set. The result should not be modified further. */
     432             :     static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
     433             :     /* Return the intersection of the 2 TypeSets. The result should not be modified further */
     434             :     static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
     435             :     /*
     436             :      * Returns a copy of TypeSet a excluding/removing the types in TypeSet b.
     437             :      * TypeSet b can only contain primitives or be any object. No support for
     438             :      * specific objects. The result should not be modified further.
     439             :      */
     440             :     static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
     441             : 
     442             :     /* Add a type to this set using the specified allocator. */
     443             :     void addType(Type type, LifoAlloc* alloc);
     444             : 
     445             :     /* Get a list of all types in this set. */
     446             :     typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
     447             :     template <class TypeListT> bool enumerateTypes(TypeListT* list) const;
     448             : 
     449             :     /*
     450             :      * Iterate through the objects in this set. getObjectCount overapproximates
     451             :      * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
     452             :      * getObject may return nullptr.
     453             :      */
     454             :     inline unsigned getObjectCount() const;
     455             :     inline ObjectKey* getObject(unsigned i) const;
     456             :     inline JSObject* getSingleton(unsigned i) const;
     457             :     inline ObjectGroup* getGroup(unsigned i) const;
     458             :     inline JSObject* getSingletonNoBarrier(unsigned i) const;
     459             :     inline ObjectGroup* getGroupNoBarrier(unsigned i) const;
     460             : 
     461             :     /* The Class of an object in this set. */
     462             :     inline const Class* getObjectClass(unsigned i) const;
     463             : 
     464        2130 :     bool canSetDefinite(unsigned slot) {
     465             :         // Note: the cast is required to work around an MSVC issue.
     466        2130 :         return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
     467             :     }
     468        1065 :     void setDefinite(unsigned slot) {
     469        1065 :         MOZ_ASSERT(canSetDefinite(slot));
     470        1065 :         flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
     471        1065 :         MOZ_ASSERT(definiteSlot() == slot);
     472        1065 :     }
     473             : 
     474             :     /* Whether any values in this set might have the specified type. */
     475             :     bool mightBeMIRType(jit::MIRType type) const;
     476             : 
     477             :     /*
     478             :      * Get whether this type set is known to be a subset of other.
     479             :      * This variant doesn't freeze constraints. That variant is called knownSubset
     480             :      */
     481             :     bool isSubset(const TypeSet* other) const;
     482             : 
     483             :     /*
     484             :      * Get whether the objects in this TypeSet are a subset of the objects
     485             :      * in other.
     486             :      */
     487             :     bool objectsAreSubset(TypeSet* other);
     488             : 
     489             :     /* Whether this TypeSet contains exactly the same types as other. */
     490        1606 :     bool equals(const TypeSet* other) const {
     491        1606 :         return this->isSubset(other) && other->isSubset(this);
     492             :     }
     493             : 
     494             :     bool objectsIntersect(const TypeSet* other) const;
     495             : 
     496             :     /* Forward all types in this set to the specified constraint. */
     497             :     bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
     498             : 
     499             :     // Clone a type set into an arbitrary allocator.
     500             :     TemporaryTypeSet* clone(LifoAlloc* alloc) const;
     501             :     bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
     502             : 
     503             :     // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
     504             :     TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
     505             :     // Create a new TemporaryTypeSet where the type has been set to object.
     506             :     TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
     507             :     TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
     508             : 
     509             :     JSCompartment* maybeCompartment();
     510             : 
     511             :     // Trigger a read barrier on all the contents of a type set.
     512             :     static void readBarrier(const TypeSet* types);
     513             : 
     514             :   protected:
     515      206179 :     uint32_t baseObjectCount() const {
     516      206179 :         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     517             :     }
     518             :     inline void setBaseObjectCount(uint32_t count);
     519             : 
     520             :     void clearObjects();
     521             : 
     522             :   public:
     523             :     static inline Type GetValueType(const Value& val);
     524             : 
     525             :     static inline bool IsUntrackedValue(const Value& val);
     526             : 
     527             :     // Get the type of a possibly optimized out or uninitialized let value.
     528             :     // This generally only happens on unconditional type monitors on bailing
     529             :     // out of Ion, such as for argument and local types.
     530             :     static inline Type GetMaybeUntrackedValueType(const Value& val);
     531             : 
     532             :     static bool IsTypeMarked(JSRuntime* rt, Type* v);
     533             :     static bool IsTypeAboutToBeFinalized(Type* v);
     534             : } JS_HAZ_GC_POINTER;
     535             : 
     536             : #if JS_BITS_PER_WORD == 32
     537             : static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4;
     538             : #else
     539             : static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4c5c6d7d8;
     540             : #endif
     541             : static const uintptr_t TypeConstraintMagic = BaseTypeInferenceMagic + 1;
     542             : static const uintptr_t ConstraintTypeSetMagic = BaseTypeInferenceMagic + 2;
     543             : 
     544             : #ifdef JS_CRASH_DIAGNOSTICS
     545             : extern void
     546             : ReportMagicWordFailure(uintptr_t actual, uintptr_t expected);
     547             : extern void
     548             : ReportMagicWordFailure(uintptr_t actual, uintptr_t expected, uintptr_t flags, uintptr_t objectSet);
     549             : #endif
     550             : 
     551             : /*
     552             :  * A constraint which listens to additions to a type set and propagates those
     553             :  * changes to other type sets.
     554             :  */
     555             : class TypeConstraint
     556             : {
     557             : #ifdef JS_CRASH_DIAGNOSTICS
     558             :     uintptr_t magic_;
     559             : #endif
     560             : 
     561             :     /* Next constraint listening to the same type set. */
     562             :     TypeConstraint* next_;
     563             : 
     564             :   public:
     565         866 :     TypeConstraint()
     566         866 :       : next_(nullptr)
     567             :     {
     568             : #ifdef JS_CRASH_DIAGNOSTICS
     569         866 :         magic_ = TypeConstraintMagic;
     570             : #endif
     571         866 :     }
     572             : 
     573        2295 :     void checkMagic() const {
     574             : #ifdef JS_CRASH_DIAGNOSTICS
     575        2295 :         if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic))
     576           0 :             ReportMagicWordFailure(magic_, TypeConstraintMagic);
     577             : #endif
     578        2295 :     }
     579             : 
     580         868 :     TypeConstraint* next() const {
     581         868 :         checkMagic();
     582         868 :         if (next_)
     583           0 :             next_->checkMagic();
     584         868 :         return next_;
     585             :     }
     586         866 :     void setNext(TypeConstraint* next) {
     587         866 :         MOZ_ASSERT(!next_);
     588         866 :         checkMagic();
     589         866 :         if (next)
     590         559 :             next->checkMagic();
     591         866 :         next_ = next;
     592         866 :     }
     593             : 
     594             :     /* Debugging name for this kind of constraint. */
     595             :     virtual const char* kind() = 0;
     596             : 
     597             :     /* Register a new type for the set this constraint is listening to. */
     598             :     virtual void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) = 0;
     599             : 
     600             :     /*
     601             :      * For constraints attached to an object property's type set, mark the
     602             :      * property as having changed somehow.
     603             :      */
     604           0 :     virtual void newPropertyState(JSContext* cx, TypeSet* source) {}
     605             : 
     606             :     /*
     607             :      * For constraints attached to the JSID_EMPTY type set on an object,
     608             :      * indicate a change in one of the object's dynamic property flags or other
     609             :      * state.
     610             :      */
     611           0 :     virtual void newObjectState(JSContext* cx, ObjectGroup* group) {}
     612             : 
     613             :     /*
     614             :      * If the data this constraint refers to is still live, copy it into the
     615             :      * zone's new allocator. Type constraints only hold weak references.
     616             :      */
     617             :     virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
     618             : 
     619             :     /* The associated compartment, if any. */
     620             :     virtual JSCompartment* maybeCompartment() = 0;
     621             : };
     622             : 
     623             : // If there is an OOM while sweeping types, the type information is deoptimized
     624             : // so that it stays correct (i.e. overapproximates the possible types in the
     625             : // zone), but constraints might not have been triggered on the deoptimization
     626             : // or even copied over completely. In this case, destroy all JIT code and new
     627             : // script information in the zone, the only things whose correctness depends on
     628             : // the type constraints.
     629             : class AutoClearTypeInferenceStateOnOOM
     630             : {
     631             :     Zone* zone;
     632             :     bool oom;
     633             : 
     634             :     AutoClearTypeInferenceStateOnOOM(const AutoClearTypeInferenceStateOnOOM&) = delete;
     635             :     void operator=(const AutoClearTypeInferenceStateOnOOM&) = delete;
     636             : 
     637             :   public:
     638             :     explicit AutoClearTypeInferenceStateOnOOM(Zone* zone);
     639             :     ~AutoClearTypeInferenceStateOnOOM();
     640             : 
     641           0 :     void setOOM() {
     642           0 :         oom = true;
     643           0 :     }
     644           0 :     bool hadOOM() const {
     645           0 :         return oom;
     646             :     }
     647             : };
     648             : 
     649             : /* Superclass common to stack and heap type sets. */
     650             : class ConstraintTypeSet : public TypeSet
     651             : {
     652             : #ifdef JS_CRASH_DIAGNOSTICS
     653             :     uintptr_t magic_;
     654             : #endif
     655             : 
     656             :   protected:
     657             :     /* Chain of constraints which propagate changes out from this type set. */
     658             :     TypeConstraint* constraintList_;
     659             : 
     660             :   public:
     661       24801 :     ConstraintTypeSet()
     662       24801 :       : constraintList_(nullptr)
     663             :     {
     664             : #ifdef JS_CRASH_DIAGNOSTICS
     665       24801 :         magic_ = ConstraintTypeSetMagic;
     666             : #endif
     667       24801 :     }
     668             : 
     669             : #ifdef JS_CRASH_DIAGNOSTICS
     670       16285 :     void initMagic() {
     671       16285 :         MOZ_ASSERT(!magic_);
     672       16285 :         magic_ = ConstraintTypeSetMagic;
     673       16285 :     }
     674             : #endif
     675             : 
     676      235107 :     void checkMagic() const {
     677             : #ifdef JS_CRASH_DIAGNOSTICS
     678      235107 :         if (MOZ_UNLIKELY(magic_ != ConstraintTypeSetMagic))
     679           0 :             ReportMagicWordFailure(magic_, ConstraintTypeSetMagic, uintptr_t(flags), uintptr_t(objectSet));
     680             : #endif
     681      235107 :     }
     682             : 
     683       58645 :     TypeConstraint* constraintList() const {
     684       58645 :         checkMagic();
     685       58645 :         if (constraintList_)
     686           2 :             constraintList_->checkMagic();
     687       58645 :         return constraintList_;
     688             :     }
     689             :     void setConstraintList(TypeConstraint* constraint) {
     690             :         MOZ_ASSERT(!constraintList_);
     691             :         checkMagic();
     692             :         if (constraint)
     693             :             constraint->checkMagic();
     694             :         constraintList_ = constraint;
     695             :     }
     696             : 
     697             :     /*
     698             :      * Add a type to this set, calling any constraint handlers if this is a new
     699             :      * possible type.
     700             :      */
     701             :     void addType(JSContext* cx, Type type);
     702             : 
     703             :     // Trigger a post barrier when writing to this set, if necessary.
     704             :     // addType(cx, type) takes care of this automatically.
     705             :     void postWriteBarrier(JSContext* cx, Type type);
     706             : 
     707             :     /* Add a new constraint to this set. */
     708             :     bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
     709             : 
     710             :     inline void sweep(JS::Zone* zone, AutoClearTypeInferenceStateOnOOM& oom);
     711             :     inline void trace(JS::Zone* zone, JSTracer* trc);
     712             : };
     713             : 
     714             : class StackTypeSet : public ConstraintTypeSet
     715             : {
     716             :   public:
     717             : };
     718             : 
     719       24801 : class HeapTypeSet : public ConstraintTypeSet
     720             : {
     721             :     inline void newPropertyState(JSContext* cx);
     722             : 
     723             :   public:
     724             :     /* Mark this type set as representing a non-data property. */
     725             :     inline void setNonDataProperty(JSContext* cx);
     726             : 
     727             :     /* Mark this type set as representing a non-writable property. */
     728             :     inline void setNonWritableProperty(JSContext* cx);
     729             : 
     730             :     // Mark this type set as being non-constant.
     731             :     inline void setNonConstantProperty(JSContext* cx);
     732             : };
     733             : 
     734             : CompilerConstraintList*
     735             : NewCompilerConstraintList(jit::TempAllocator& alloc);
     736             : 
     737             : class TemporaryTypeSet : public TypeSet
     738             : {
     739             :   public:
     740        3247 :     TemporaryTypeSet() {}
     741             :     TemporaryTypeSet(LifoAlloc* alloc, Type type);
     742             : 
     743        6764 :     TemporaryTypeSet(uint32_t flags, ObjectKey** objectSet) {
     744        6764 :         this->flags = flags;
     745        6764 :         this->objectSet = objectSet;
     746        6764 :     }
     747             : 
     748         772 :     TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type)
     749         772 :       : TemporaryTypeSet(alloc, PrimitiveType(ValueTypeFromMIRType(type)))
     750             :     {
     751         772 :         MOZ_ASSERT(type != jit::MIRType::Value);
     752         772 :     }
     753             : 
     754             :     /*
     755             :      * Constraints for JIT compilation.
     756             :      *
     757             :      * Methods for JIT compilation. These must be used when a script is
     758             :      * currently being compiled (see AutoEnterCompilation) and will add
     759             :      * constraints ensuring that if the return value change in the future due
     760             :      * to new type information, the script's jitcode will be discarded.
     761             :      */
     762             : 
     763             :     /* Get any type tag which all values in this set must have. */
     764             :     jit::MIRType getKnownMIRType();
     765             : 
     766             :     bool isMagicArguments() { return getKnownMIRType() == jit::MIRType::MagicOptimizedArguments; }
     767             : 
     768             :     /* Whether this value may be an object. */
     769         678 :     bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
     770             : 
     771             :     /*
     772             :      * Whether this typeset represents a potentially sentineled object value:
     773             :      * the value may be an object or null or undefined.
     774             :      * Returns false if the value cannot ever be an object.
     775             :      */
     776         405 :     bool objectOrSentinel() {
     777         405 :         TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
     778         405 :         if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
     779           0 :             return false;
     780             : 
     781         405 :         return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
     782             :     }
     783             : 
     784             :     /* Whether the type set contains objects with any of a set of flags. */
     785             :     bool hasObjectFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
     786             : 
     787             :     /* Get the class shared by all objects in this set, or nullptr. */
     788             :     const Class* getKnownClass(CompilerConstraintList* constraints);
     789             : 
     790             :     /* Result returned from forAllClasses */
     791             :     enum ForAllResult {
     792             :         EMPTY=1,                // Set empty
     793             :         ALL_TRUE,               // Set not empty and predicate returned true for all classes
     794             :         ALL_FALSE,              // Set not empty and predicate returned false for all classes
     795             :         MIXED,                  // Set not empty and predicate returned false for some classes
     796             :                                 // and true for others, or set contains an unknown or non-object
     797             :                                 // type
     798             :     };
     799             : 
     800             :     /* Apply func to the members of the set and return an appropriate result.
     801             :      * The iteration may end early if the result becomes known early.
     802             :      */
     803             :     ForAllResult forAllClasses(CompilerConstraintList* constraints,
     804             :                                bool (*func)(const Class* clasp));
     805             : 
     806             :     /*
     807             :      * Returns true if all objects in this set have the same prototype, and
     808             :      * assigns this object to *proto. The proto can be nullptr.
     809             :      */
     810             :     bool getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto);
     811             : 
     812             :     /* Whether the buffer mapped by a TypedArray is shared memory or not */
     813             :     enum TypedArraySharedness {
     814             :         UnknownSharedness=1,    // We can't determine sharedness
     815             :         KnownShared,            // We know for sure the buffer is shared
     816             :         KnownUnshared           // We know for sure the buffer is unshared
     817             :     };
     818             : 
     819             :     /* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
     820             :      * If there is such a common type and sharedness is not nullptr then
     821             :      * *sharedness is set to what we know about the sharedness of the memory.
     822             :      */
     823             :     Scalar::Type getTypedArrayType(CompilerConstraintList* constraints,
     824             :                                    TypedArraySharedness* sharedness = nullptr);
     825             : 
     826             :     /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
     827             :     bool isDOMClass(CompilerConstraintList* constraints);
     828             : 
     829             :     /* Whether clasp->isCallable() is true for one or more objects in this set. */
     830             :     bool maybeCallable(CompilerConstraintList* constraints);
     831             : 
     832             :     /* Whether clasp->isProxy() might be true for one or more objects in this set. */
     833             :     bool maybeProxy(CompilerConstraintList* constraints);
     834             : 
     835             :     /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
     836             :     bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
     837             : 
     838             :     /* Get the single value which can appear in this type set, otherwise nullptr. */
     839             :     JSObject* maybeSingleton();
     840             :     ObjectKey* maybeSingleObject();
     841             : 
     842             :     /* Whether any objects in the type set needs a barrier on id. */
     843             :     bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
     844             : 
     845             :     /*
     846             :      * Whether this set contains all types in other, except (possibly) the
     847             :      * specified type.
     848             :      */
     849             :     bool filtersType(const TemporaryTypeSet* other, Type type) const;
     850             : 
     851             :     enum DoubleConversion {
     852             :         /* All types in the set should use eager double conversion. */
     853             :         AlwaysConvertToDoubles,
     854             : 
     855             :         /* Some types in the set should use eager double conversion. */
     856             :         MaybeConvertToDoubles,
     857             : 
     858             :         /* No types should use eager double conversion. */
     859             :         DontConvertToDoubles,
     860             : 
     861             :         /* Some types should use eager double conversion, others cannot. */
     862             :         AmbiguousDoubleConversion
     863             :     };
     864             : 
     865             :     /*
     866             :      * Whether known double optimizations are possible for element accesses on
     867             :      * objects in this type set.
     868             :      */
     869             :     DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
     870             : 
     871             :   private:
     872             :     void getTypedArraySharedness(CompilerConstraintList* constraints,
     873             :                                  TypedArraySharedness* sharedness);
     874             : };
     875             : 
     876             : bool
     877             : AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
     878             : 
     879             : bool
     880             : AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
     881             :                                      JSScript* script, JSScript* calleeScript);
     882             : 
     883             : // For groups where only a small number of objects have been allocated, this
     884             : // structure keeps track of all objects in the group. Once COUNT objects have
     885             : // been allocated, this structure is cleared and the objects are analyzed, to
     886             : // perform the new script properties analyses or determine if an unboxed
     887             : // representation can be used.
     888             : class PreliminaryObjectArray
     889             : {
     890             :   public:
     891             :     static const uint32_t COUNT = 20;
     892             : 
     893             :   private:
     894             :     // All objects with the type which have been allocated. The pointers in
     895             :     // this array are weak.
     896             :     JSObject* objects[COUNT];
     897             : 
     898             :   public:
     899        3473 :     PreliminaryObjectArray() {
     900        3473 :         mozilla::PodZero(this);
     901        3473 :     }
     902             : 
     903             :     void registerNewObject(JSObject* res);
     904             :     void unregisterObject(JSObject* obj);
     905             : 
     906        3091 :     JSObject* get(size_t i) const {
     907        3091 :         MOZ_ASSERT(i < COUNT);
     908        3091 :         return objects[i];
     909             :     }
     910             : 
     911             :     bool full() const;
     912             :     bool empty() const;
     913             :     void sweep();
     914             : };
     915             : 
     916          58 : class PreliminaryObjectArrayWithTemplate : public PreliminaryObjectArray
     917             : {
     918             :     HeapPtr<Shape*> shape_;
     919             : 
     920             :   public:
     921        3278 :     explicit PreliminaryObjectArrayWithTemplate(Shape* shape)
     922        3278 :       : shape_(shape)
     923        3278 :     {}
     924             : 
     925           0 :     void clear() {
     926           0 :         shape_.init(nullptr);
     927           0 :     }
     928             : 
     929        2607 :     Shape* shape() {
     930        2607 :         return shape_;
     931             :     }
     932             : 
     933             :     void maybeAnalyze(JSContext* cx, ObjectGroup* group, bool force = false);
     934             : 
     935             :     void trace(JSTracer* trc);
     936             : 
     937             :     static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects);
     938             : };
     939             : 
     940             : // New script properties analyses overview.
     941             : //
     942             : // When constructing objects using 'new' on a script, we attempt to determine
     943             : // the properties which that object will eventually have. This is done via two
     944             : // analyses. One of these, the definite properties analysis, is static, and the
     945             : // other, the acquired properties analysis, is dynamic. As objects are
     946             : // constructed using 'new' on some script to create objects of group G, our
     947             : // analysis strategy is as follows:
     948             : //
     949             : // - When the first objects are created, no analysis is immediately performed.
     950             : //   Instead, all objects of group G are accumulated in an array.
     951             : //
     952             : // - After a certain number of such objects have been created, the definite
     953             : //   properties analysis is performed. This analyzes the body of the
     954             : //   constructor script and any other functions it calls to look for properties
     955             : //   which will definitely be added by the constructor in a particular order,
     956             : //   creating an object with shape S.
     957             : //
     958             : // - The properties in S are compared with the greatest common prefix P of the
     959             : //   shapes of the objects that have been created. If P has more properties
     960             : //   than S, the acquired properties analysis is performed.
     961             : //
     962             : // - The acquired properties analysis marks all properties in P as definite
     963             : //   in G, and creates a new group IG for objects which are partially
     964             : //   initialized. Objects of group IG are initially created with shape S, and if
     965             : //   they are later given shape P, their group can be changed to G.
     966             : //
     967             : // For objects which are rarely created, the definite properties analysis can
     968             : // be triggered after only one or a few objects have been allocated, when code
     969             : // being Ion compiled might access them. In this case type information in the
     970             : // constructor might not be good enough for the definite properties analysis to
     971             : // compute useful information, but the acquired properties analysis will still
     972             : // be able to identify definite properties in this case.
     973             : //
     974             : // This layered approach is designed to maximize performance on easily
     975             : // analyzable code, while still allowing us to determine definite properties
     976             : // robustly when code consistently adds the same properties to objects, but in
     977             : // complex ways which can't be understood statically.
     978             : class TypeNewScript
     979             : {
     980             :   public:
     981             :     struct Initializer {
     982             :         enum Kind {
     983             :             SETPROP,
     984             :             SETPROP_FRAME,
     985             :             DONE
     986             :         } kind;
     987             :         uint32_t offset;
     988           0 :         Initializer(Kind kind, uint32_t offset)
     989           0 :           : kind(kind), offset(offset)
     990           0 :         {}
     991             :     };
     992             : 
     993             :   private:
     994             :     // Scripted function which this information was computed for.
     995             :     HeapPtr<JSFunction*> function_;
     996             : 
     997             :     // Any preliminary objects with the type. The analyses are not performed
     998             :     // until this array is cleared.
     999             :     PreliminaryObjectArray* preliminaryObjects;
    1000             : 
    1001             :     // After the new script properties analyses have been performed, a template
    1002             :     // object to use for newly constructed objects. The shape of this object
    1003             :     // reflects all definite properties the object will have, and the
    1004             :     // allocation kind to use. This is null if the new objects have an unboxed
    1005             :     // layout, in which case the UnboxedLayout provides the initial structure
    1006             :     // of the object.
    1007             :     HeapPtr<PlainObject*> templateObject_;
    1008             : 
    1009             :     // Order in which definite properties become initialized. We need this in
    1010             :     // case the definite properties are invalidated (such as by adding a setter
    1011             :     // to an object on the prototype chain) while an object is in the middle of
    1012             :     // being initialized, so we can walk the stack and fixup any objects which
    1013             :     // look for in-progress objects which were prematurely set with an incorrect
    1014             :     // shape. Property assignments in inner frames are preceded by a series of
    1015             :     // SETPROP_FRAME entries specifying the stack down to the frame containing
    1016             :     // the write.
    1017             :     Initializer* initializerList;
    1018             : 
    1019             :     // If there are additional properties found by the acquired properties
    1020             :     // analysis which were not found by the definite properties analysis, this
    1021             :     // shape contains all such additional properties (plus the definite
    1022             :     // properties). When an object of this group acquires this shape, it is
    1023             :     // fully initialized and its group can be changed to initializedGroup.
    1024             :     HeapPtr<Shape*> initializedShape_;
    1025             : 
    1026             :     // Group with definite properties set for all properties found by
    1027             :     // both the definite and acquired properties analyses.
    1028             :     HeapPtr<ObjectGroup*> initializedGroup_;
    1029             : 
    1030             :   public:
    1031         195 :     TypeNewScript() { mozilla::PodZero(this); }
    1032          16 :     ~TypeNewScript() {
    1033           8 :         js_delete(preliminaryObjects);
    1034           8 :         js_free(initializerList);
    1035           8 :     }
    1036             : 
    1037           0 :     void clear() {
    1038           0 :         function_.init(nullptr);
    1039           0 :         templateObject_.init(nullptr);
    1040           0 :         initializedShape_.init(nullptr);
    1041           0 :         initializedGroup_.init(nullptr);
    1042           0 :     }
    1043             : 
    1044             :     static void writeBarrierPre(TypeNewScript* newScript);
    1045             : 
    1046        2677 :     bool analyzed() const {
    1047        2677 :         return preliminaryObjects == nullptr;
    1048             :     }
    1049             : 
    1050          26 :     PlainObject* templateObject() const {
    1051          26 :         return templateObject_;
    1052             :     }
    1053             : 
    1054        1488 :     Shape* initializedShape() const {
    1055        1488 :         return initializedShape_;
    1056             :     }
    1057             : 
    1058        1067 :     ObjectGroup* initializedGroup() const {
    1059        1067 :         return initializedGroup_;
    1060             :     }
    1061             : 
    1062          19 :     JSFunction* function() const {
    1063          19 :         return function_;
    1064             :     }
    1065             : 
    1066             :     void trace(JSTracer* trc);
    1067             :     void sweep();
    1068             : 
    1069             :     void registerNewObject(PlainObject* res);
    1070             :     bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
    1071             : 
    1072             :     bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
    1073             : 
    1074             :     static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
    1075             :     static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
    1076             :                                             PlainObject* templateObject);
    1077             : 
    1078             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    1079             : 
    1080          13 :     static size_t offsetOfPreliminaryObjects() {
    1081          13 :         return offsetof(TypeNewScript, preliminaryObjects);
    1082             :     }
    1083             : };
    1084             : 
    1085             : /* Is this a reasonable PC to be doing inlining on? */
    1086             : inline bool isInlinableCall(jsbytecode* pc);
    1087             : 
    1088             : bool
    1089             : ClassCanHaveExtraProperties(const Class* clasp);
    1090             : 
    1091             : /*
    1092             :  * Information about the result of the compilation of a script.  This structure
    1093             :  * stored in the TypeCompartment is indexed by the RecompileInfo. This
    1094             :  * indirection enables the invalidation of all constraints related to the same
    1095             :  * compilation.
    1096             :  */
    1097             : class CompilerOutput
    1098             : {
    1099             :     // If this compilation has not been invalidated, the associated script and
    1100             :     // kind of compilation being performed.
    1101             :     JSScript* script_;
    1102             : 
    1103             :     // Whether this compilation is about to be invalidated.
    1104             :     bool pendingInvalidation_ : 1;
    1105             : 
    1106             :     // During sweeping, the list of compiler outputs is compacted and invalidated
    1107             :     // outputs are removed. This gives the new index for a valid compiler output.
    1108             :     uint32_t sweepIndex_ : 31;
    1109             : 
    1110             :   public:
    1111             :     static const uint32_t INVALID_SWEEP_INDEX = static_cast<uint32_t>(1 << 31) - 1;
    1112             : 
    1113             :     CompilerOutput()
    1114             :       : script_(nullptr),
    1115             :         pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
    1116             :     {}
    1117             : 
    1118           7 :     explicit CompilerOutput(JSScript* script)
    1119           7 :       : script_(script),
    1120           7 :         pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
    1121           7 :     {}
    1122             : 
    1123          20 :     JSScript* script() const { return script_; }
    1124             : 
    1125             :     inline jit::IonScript* ion() const;
    1126             : 
    1127          26 :     bool isValid() const {
    1128          26 :         return script_ != nullptr;
    1129             :     }
    1130           7 :     void invalidate() {
    1131           7 :         script_ = nullptr;
    1132           7 :     }
    1133             : 
    1134           0 :     void setPendingInvalidation() {
    1135           0 :         pendingInvalidation_ = true;
    1136           0 :     }
    1137           5 :     bool pendingInvalidation() {
    1138           5 :         return pendingInvalidation_;
    1139             :     }
    1140             : 
    1141           0 :     void setSweepIndex(uint32_t index) {
    1142           0 :         if (index >= INVALID_SWEEP_INDEX)
    1143           0 :             MOZ_CRASH();
    1144           0 :         sweepIndex_ = index;
    1145           0 :     }
    1146           0 :     uint32_t sweepIndex() {
    1147           0 :         MOZ_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
    1148           0 :         return sweepIndex_;
    1149             :     }
    1150             : };
    1151             : 
    1152             : class RecompileInfo
    1153             : {
    1154             :     // Index in the TypeZone's compilerOutputs or sweepCompilerOutputs arrays,
    1155             :     // depending on the generation value.
    1156             :     uint32_t outputIndex : 31;
    1157             : 
    1158             :     // If out of sync with the TypeZone's generation, this index is for the
    1159             :     // zone's sweepCompilerOutputs rather than compilerOutputs.
    1160             :     uint32_t generation : 1;
    1161             : 
    1162             :   public:
    1163           7 :     RecompileInfo(uint32_t outputIndex, uint32_t generation)
    1164           7 :       : outputIndex(outputIndex), generation(generation)
    1165           7 :     {}
    1166             : 
    1167          12 :     RecompileInfo()
    1168          12 :       : outputIndex(JS_BITMASK(31)), generation(0)
    1169          12 :     {}
    1170             : 
    1171          16 :     bool operator==(const RecompileInfo& other) const {
    1172          16 :         return outputIndex == other.outputIndex && generation == other.generation;
    1173             :     }
    1174             : 
    1175             :     CompilerOutput* compilerOutput(TypeZone& types) const;
    1176             :     CompilerOutput* compilerOutput(JSContext* cx) const;
    1177             :     bool shouldSweep(TypeZone& types);
    1178             : };
    1179             : 
    1180             : // The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a
    1181             : // single IonScript doesn't require an allocation.
    1182             : typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector;
    1183             : 
    1184             : /* Persistent type information for a script, retained across GCs. */
    1185           0 : class TypeScript
    1186             : {
    1187             :     friend class ::JSScript;
    1188             : 
    1189             :     // The freeze constraints added to stack type sets will only directly
    1190             :     // invalidate the script containing those stack type sets. This Vector
    1191             :     // contains compilations that inlined this script, so we can invalidate
    1192             :     // them as well.
    1193             :     RecompileInfoVector inlinedCompilations_;
    1194             : 
    1195             :     // Variable-size array
    1196             :     StackTypeSet typeArray_[1];
    1197             : 
    1198             :   public:
    1199           4 :     RecompileInfoVector& inlinedCompilations() {
    1200           4 :         return inlinedCompilations_;
    1201             :     }
    1202          24 :     MOZ_MUST_USE bool addInlinedCompilation(RecompileInfo info) {
    1203          24 :         if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info)
    1204          15 :             return true;
    1205           9 :         return inlinedCompilations_.append(info);
    1206             :     }
    1207             : 
    1208             :     /* Array of type sets for variables and JOF_TYPESET ops. */
    1209       31814 :     StackTypeSet* typeArray() const {
    1210             :         // Ensure typeArray_ is the last data member of TypeScript.
    1211             :         JS_STATIC_ASSERT(sizeof(TypeScript) ==
    1212             :                          sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
    1213       31814 :         return const_cast<StackTypeSet*>(typeArray_);
    1214             :     }
    1215             : 
    1216         705 :     static inline size_t SizeIncludingTypeArray(size_t arraySize) {
    1217             :         // Ensure typeArray_ is the last data member of TypeScript.
    1218             :         JS_STATIC_ASSERT(sizeof(TypeScript) ==
    1219             :             sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
    1220         705 :         return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
    1221             :     }
    1222             : 
    1223             :     static inline unsigned NumTypeSets(JSScript* script);
    1224             : 
    1225             :     static inline StackTypeSet* ThisTypes(JSScript* script);
    1226             :     static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i);
    1227             : 
    1228             :     /* Get the type set for values observed at an opcode. */
    1229             :     static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc);
    1230             : 
    1231             :     template <typename TYPESET>
    1232             :     static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
    1233             :                                          uint32_t* hint, TYPESET* typeArray);
    1234             : 
    1235             :     /*
    1236             :      * Monitor a bytecode pushing any value. This must be called for any opcode
    1237             :      * which is JOF_TYPESET, and where either the script has not been analyzed
    1238             :      * by type inference or where the pc has type barriers. For simplicity, we
    1239             :      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
    1240             :      * and only look at barriers when generating JIT code for the script.
    1241             :      */
    1242             :     static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
    1243             :                                const js::Value& val);
    1244             :     static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
    1245             :                                TypeSet::Type type);
    1246             :     static inline void Monitor(JSContext* cx, const js::Value& rval);
    1247             : 
    1248             :     static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
    1249             :                                StackTypeSet* types, const js::Value& val);
    1250             : 
    1251             :     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
    1252             :     static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
    1253             : 
    1254             :     /* Add a type for a variable in a script. */
    1255             :     static inline void SetThis(JSContext* cx, JSScript* script, TypeSet::Type type);
    1256             :     static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
    1257             :     static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
    1258             :                                    TypeSet::Type type);
    1259             :     static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
    1260             :                                    const js::Value& value);
    1261             : 
    1262             :     /*
    1263             :      * Freeze all the stack type sets in a script, for a compilation. Returns
    1264             :      * copies of the type sets which will be checked against the actual ones
    1265             :      * under FinishCompilation, to detect any type changes.
    1266             :      */
    1267             :     static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
    1268             :                                TemporaryTypeSet** pThisTypes,
    1269             :                                TemporaryTypeSet** pArgTypes,
    1270             :                                TemporaryTypeSet** pBytecodeTypes);
    1271             : 
    1272             :     static void Purge(JSContext* cx, HandleScript script);
    1273             : 
    1274             :     void destroy();
    1275             : 
    1276           0 :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    1277           0 :         return mallocSizeOf(this);
    1278             :     }
    1279             : 
    1280             : #ifdef DEBUG
    1281             :     void printTypes(JSContext* cx, HandleScript script) const;
    1282             : #endif
    1283             : };
    1284             : 
    1285             : void
    1286             : FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
    1287             : 
    1288             : class RecompileInfo;
    1289             : 
    1290             : // Allocate a CompilerOutput for a finished compilation and generate the type
    1291             : // constraints for the compilation. Sets |isValidOut| based on whether the type
    1292             : // constraints still hold.
    1293             : bool
    1294             : FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
    1295             :                   RecompileInfo* precompileInfo, bool* isValidOut);
    1296             : 
    1297             : // Reset any CompilerOutput present for a script.
    1298             : void
    1299             : InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
    1300             : 
    1301             : // Update the actual types in any scripts queried by constraints with any
    1302             : // speculative types added during the definite properties analysis.
    1303             : void
    1304             : FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
    1305             : 
    1306             : // Representation of a heap type property which may or may not be instantiated.
    1307             : // Heap properties for singleton types are instantiated lazily as they are used
    1308             : // by the compiler, but this is only done on the active thread. If we are
    1309             : // compiling off thread and use a property which has not yet been instantiated,
    1310             : // it will be treated as empty and non-configured and will be instantiated when
    1311             : // rejoining to the active thread. If it is in fact not empty, the compilation
    1312             : // will fail; to avoid this, we try to instantiate singleton property types
    1313             : // during generation of baseline caches.
    1314             : class HeapTypeSetKey
    1315             : {
    1316             :     friend class TypeSet::ObjectKey;
    1317             : 
    1318             :     // Object and property being accessed.
    1319             :     TypeSet::ObjectKey* object_;
    1320             :     jsid id_;
    1321             : 
    1322             :     // If instantiated, the underlying heap type set.
    1323             :     HeapTypeSet* maybeTypes_;
    1324             : 
    1325             :   public:
    1326        1312 :     HeapTypeSetKey()
    1327        1312 :       : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
    1328        1312 :     {}
    1329             : 
    1330        2352 :     TypeSet::ObjectKey* object() const { return object_; }
    1331         274 :     jsid id() const { return id_; }
    1332             : 
    1333        4404 :     HeapTypeSet* maybeTypes() const {
    1334        4404 :         if (maybeTypes_)
    1335        3329 :             maybeTypes_->checkMagic();
    1336        4404 :         return maybeTypes_;
    1337             :     }
    1338             : 
    1339             :     bool instantiate(JSContext* cx);
    1340             : 
    1341             :     void freeze(CompilerConstraintList* constraints);
    1342             :     jit::MIRType knownMIRType(CompilerConstraintList* constraints);
    1343             :     bool nonData(CompilerConstraintList* constraints);
    1344             :     bool nonWritable(CompilerConstraintList* constraints);
    1345             :     bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
    1346             :     bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
    1347             :     JSObject* singleton(CompilerConstraintList* constraints);
    1348             :     bool needsBarrier(CompilerConstraintList* constraints);
    1349             :     bool constant(CompilerConstraintList* constraints, Value* valOut);
    1350             :     bool couldBeConstant(CompilerConstraintList* constraints);
    1351             : };
    1352             : 
    1353             : struct AutoEnterAnalysis;
    1354             : 
    1355             : class TypeZone
    1356             : {
    1357             :     JS::Zone* const zone_;
    1358             : 
    1359             :     /* Pool for type information in this zone. */
    1360             :     static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
    1361             :     ZoneGroupData<LifoAlloc> typeLifoAlloc_;
    1362             : 
    1363             :   public:
    1364             :     // Current generation for sweeping.
    1365             :     ZoneGroupOrGCTaskOrIonCompileData<uint32_t> generation;
    1366             : 
    1367             :     /*
    1368             :      * All Ion compilations that have occured in this zone, for indexing via
    1369             :      * RecompileInfo. This includes both valid and invalid compilations, though
    1370             :      * invalidated compilations are swept on GC.
    1371             :      */
    1372             :     typedef Vector<CompilerOutput, 4, SystemAllocPolicy> CompilerOutputVector;
    1373             :     ZoneGroupData<CompilerOutputVector*> compilerOutputs;
    1374             : 
    1375             :     // During incremental sweeping, allocator holding the old type information
    1376             :     // for the zone.
    1377             :     ZoneGroupData<LifoAlloc> sweepTypeLifoAlloc;
    1378             : 
    1379             :     // During incremental sweeping, the old compiler outputs for use by
    1380             :     // recompile indexes with a stale generation.
    1381             :     ZoneGroupData<CompilerOutputVector*> sweepCompilerOutputs;
    1382             : 
    1383             :     // During incremental sweeping, whether to try to destroy all type
    1384             :     // information attached to scripts.
    1385             :     ZoneGroupData<bool> sweepReleaseTypes;
    1386             : 
    1387             :     ZoneGroupData<bool> sweepingTypes;
    1388             : 
    1389             :     // The topmost AutoEnterAnalysis on the stack, if there is one.
    1390             :     ZoneGroupData<AutoEnterAnalysis*> activeAnalysis;
    1391             : 
    1392             :     explicit TypeZone(JS::Zone* zone);
    1393             :     ~TypeZone();
    1394             : 
    1395           0 :     JS::Zone* zone() const { return zone_; }
    1396             : 
    1397       85137 :     LifoAlloc& typeLifoAlloc() {
    1398             : #ifdef JS_CRASH_DIAGNOSTICS
    1399       85137 :         MOZ_RELEASE_ASSERT(CurrentThreadCanAccessZone(zone_));
    1400             : #endif
    1401       85137 :         return typeLifoAlloc_.ref();
    1402             :     }
    1403             : 
    1404             :     void beginSweep(FreeOp* fop, bool releaseTypes, AutoClearTypeInferenceStateOnOOM& oom);
    1405             :     void endSweep(JSRuntime* rt);
    1406             :     void clearAllNewScriptsOnOOM();
    1407             : 
    1408             :     /* Mark a script as needing recompilation once inference has finished. */
    1409             :     void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
    1410             :     void addPendingRecompile(JSContext* cx, JSScript* script);
    1411             : 
    1412             :     void processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles);
    1413             : 
    1414           0 :     void setSweepingTypes(bool sweeping) {
    1415           0 :         MOZ_RELEASE_ASSERT(sweepingTypes != sweeping);
    1416           0 :         sweepingTypes = sweeping;
    1417           0 :     }
    1418             : };
    1419             : 
    1420             : enum SpewChannel {
    1421             :     ISpewOps,      /* ops: New constraints and types. */
    1422             :     ISpewResult,   /* result: Final type sets. */
    1423             :     SPEW_COUNT
    1424             : };
    1425             : 
    1426             : #ifdef DEBUG
    1427             : 
    1428             : bool InferSpewActive(SpewChannel channel);
    1429             : const char * InferSpewColorReset();
    1430             : const char * InferSpewColor(TypeConstraint* constraint);
    1431             : const char * InferSpewColor(TypeSet* types);
    1432             : 
    1433             : #define InferSpew(channel, ...) if (InferSpewActive(channel)) { InferSpewImpl(__VA_ARGS__); } else {}
    1434             : void InferSpewImpl(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2);
    1435             : 
    1436             : /* Check that the type property for id in group contains value. */
    1437             : bool ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value);
    1438             : 
    1439             : #else
    1440             : 
    1441             : inline const char * InferSpewColorReset() { return nullptr; }
    1442             : inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
    1443             : inline const char * InferSpewColor(TypeSet* types) { return nullptr; }
    1444             : 
    1445             : #define InferSpew(channel, ...) do {} while (0)
    1446             : 
    1447             : #endif
    1448             : 
    1449             : // Prints type information for a context if spew is enabled or force is set.
    1450             : void
    1451             : PrintTypes(JSContext* cx, JSCompartment* comp, bool force);
    1452             : 
    1453             : } /* namespace js */
    1454             : 
    1455             : // JS::ubi::Nodes can point to object groups; they're js::gc::Cell instances
    1456             : // with no associated compartment.
    1457             : namespace JS {
    1458             : namespace ubi {
    1459             : 
    1460             : template<>
    1461             : class Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> {
    1462             :   protected:
    1463           0 :     explicit Concrete(js::ObjectGroup *ptr) : TracerConcrete<js::ObjectGroup>(ptr) { }
    1464             : 
    1465             :   public:
    1466           0 :     static void construct(void *storage, js::ObjectGroup *ptr) { new (storage) Concrete(ptr); }
    1467             : 
    1468             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1469             : 
    1470           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1471             :     static const char16_t concreteTypeName[];
    1472             : };
    1473             : 
    1474             : } // namespace ubi
    1475             : } // namespace JS
    1476             : 
    1477             : #endif /* vm_TypeInference_h */

Generated by: LCOV version 1.13