js/src/jsinfer.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* Definitions related to javascript type inference. */
     9 #ifndef jsinfer_h
    10 #define jsinfer_h
    12 #include "mozilla/MemoryReporting.h"
    13 #include "mozilla/TypedEnum.h"
    15 #include "jsalloc.h"
    16 #include "jsfriendapi.h"
    17 #include "jstypes.h"
    19 #include "ds/IdValuePair.h"
    20 #include "ds/LifoAlloc.h"
    21 #include "gc/Barrier.h"
    22 #include "gc/Marking.h"
    23 #include "jit/IonTypes.h"
    24 #include "js/Utility.h"
    25 #include "js/Vector.h"
    27 namespace js {
    29 class TypeDescr;
    31 class TaggedProto
    32 {
    33   public:
    34     static JSObject * const LazyProto;
    36     TaggedProto() : proto(nullptr) {}
    37     TaggedProto(JSObject *proto) : proto(proto) {}
    39     uintptr_t toWord() const { return uintptr_t(proto); }
    41     bool isLazy() const {
    42         return proto == LazyProto;
    43     }
    44     bool isObject() const {
    45         /* Skip nullptr and LazyProto. */
    46         return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
    47     }
    48     JSObject *toObject() const {
    49         JS_ASSERT(isObject());
    50         return proto;
    51     }
    52     JSObject *toObjectOrNull() const {
    53         JS_ASSERT(!proto || isObject());
    54         return proto;
    55     }
    56     JSObject *raw() const { return proto; }
    58     bool operator ==(const TaggedProto &other) { return proto == other.proto; }
    59     bool operator !=(const TaggedProto &other) { return proto != other.proto; }
    61   private:
    62     JSObject *proto;
    63 };
    65 template <>
    66 struct RootKind<TaggedProto>
    67 {
    68     static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
    69 };
    71 template <> struct GCMethods<const TaggedProto>
    72 {
    73     static TaggedProto initial() { return TaggedProto(); }
    74     static ThingRootKind kind() { return THING_ROOT_OBJECT; }
    75     static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
    76 };
    78 template <> struct GCMethods<TaggedProto>
    79 {
    80     static TaggedProto initial() { return TaggedProto(); }
    81     static ThingRootKind kind() { return THING_ROOT_OBJECT; }
    82     static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
    83 };
    85 template<class Outer>
    86 class TaggedProtoOperations
    87 {
    88     const TaggedProto *value() const {
    89         return static_cast<const Outer*>(this)->extract();
    90     }
    92   public:
    93     uintptr_t toWord() const { return value()->toWord(); }
    94     inline bool isLazy() const { return value()->isLazy(); }
    95     inline bool isObject() const { return value()->isObject(); }
    96     inline JSObject *toObject() const { return value()->toObject(); }
    97     inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
    98     JSObject *raw() const { return value()->raw(); }
    99 };
   101 template <>
   102 class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> >
   103 {
   104     friend class TaggedProtoOperations<Handle<TaggedProto> >;
   105     const TaggedProto * extract() const {
   106         return static_cast<const Handle<TaggedProto>*>(this)->address();
   107     }
   108 };
   110 template <>
   111 class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> >
   112 {
   113     friend class TaggedProtoOperations<Rooted<TaggedProto> >;
   114     const TaggedProto *extract() const {
   115         return static_cast<const Rooted<TaggedProto> *>(this)->address();
   116     }
   117 };
   119 class CallObject;
   121 /*
   122  * Execution Mode Overview
   123  *
   124  * JavaScript code can execute either sequentially or in parallel, such as in
   125  * PJS. Functions which behave identically in either execution mode can take a
   126  * ThreadSafeContext, and functions which have similar but not identical
   127  * behavior between execution modes can be templated on the mode. Such
   128  * functions use a context parameter type from ExecutionModeTraits below
   129  * indicating whether they are only permitted constrained operations (such as
   130  * thread safety, and side effects limited to being thread-local), or whether
   131  * they can have arbitrary side effects.
   132  */
   134 enum ExecutionMode {
   135     /* Normal JavaScript execution. */
   136     SequentialExecution,
   138     /*
   139      * JavaScript code to be executed in parallel worker threads in PJS in a
   140      * fork join fashion.
   141      */
   142     ParallelExecution,
   144     /*
   145      * Modes after this point are internal and are not counted in
   146      * NumExecutionModes below.
   147      */
   149     /*
   150      * MIR analysis performed when invoking 'new' on a script, to determine
   151      * definite properties. Used by the optimizing JIT.
   152      */
   153     DefinitePropertiesAnalysis,
   155     /*
   156      * MIR analysis performed when executing a script which uses its arguments,
   157      * when it is not known whether a lazy arguments value can be used.
   158      */
   159     ArgumentsUsageAnalysis
   160 };
   162 /*
   163  * Not as part of the enum so we don't get warnings about unhandled enum
   164  * values.
   165  */
   166 static const unsigned NumExecutionModes = ParallelExecution + 1;
   168 template <ExecutionMode mode>
   169 struct ExecutionModeTraits
   170 {
   171 };
   173 template <> struct ExecutionModeTraits<SequentialExecution>
   174 {
   175     typedef JSContext * ContextType;
   176     typedef ExclusiveContext * ExclusiveContextType;
   178     static inline JSContext *toContextType(ExclusiveContext *cx);
   179 };
   181 template <> struct ExecutionModeTraits<ParallelExecution>
   182 {
   183     typedef ForkJoinContext * ContextType;
   184     typedef ForkJoinContext * ExclusiveContextType;
   186     static inline ForkJoinContext *toContextType(ForkJoinContext *cx) { return cx; }
   187 };
   189 namespace jit {
   190     struct IonScript;
   191     class IonAllocPolicy;
   192     class TempAllocator;
   193 }
   195 namespace types {
   197 class TypeZone;
   198 class TypeSet;
   199 class TypeObjectKey;
   201 /*
   202  * Information about a single concrete type. We pack this into a single word,
   203  * where small values are particular primitive or other singleton types, and
   204  * larger values are either specific JS objects or type objects.
   205  */
   206 class Type
   207 {
   208     uintptr_t data;
   209     Type(uintptr_t data) : data(data) {}
   211   public:
   213     uintptr_t raw() const { return data; }
   215     bool isPrimitive() const {
   216         return data < JSVAL_TYPE_OBJECT;
   217     }
   219     bool isPrimitive(JSValueType type) const {
   220         JS_ASSERT(type < JSVAL_TYPE_OBJECT);
   221         return (uintptr_t) type == data;
   222     }
   224     JSValueType primitive() const {
   225         JS_ASSERT(isPrimitive());
   226         return (JSValueType) data;
   227     }
   229     bool isMagicArguments() const {
   230         return primitive() == JSVAL_TYPE_MAGIC;
   231     }
   233     bool isSomeObject() const {
   234         return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
   235     }
   237     bool isAnyObject() const {
   238         return data == JSVAL_TYPE_OBJECT;
   239     }
   241     bool isUnknown() const {
   242         return data == JSVAL_TYPE_UNKNOWN;
   243     }
   245     /* Accessors for types that are either JSObject or TypeObject. */
   247     bool isObject() const {
   248         JS_ASSERT(!isAnyObject() && !isUnknown());
   249         return data > JSVAL_TYPE_UNKNOWN;
   250     }
   252     bool isObjectUnchecked() const {
   253         return data > JSVAL_TYPE_UNKNOWN;
   254     }
   256     inline TypeObjectKey *objectKey() const;
   258     /* Accessors for JSObject types */
   260     bool isSingleObject() const {
   261         return isObject() && !!(data & 1);
   262     }
   264     inline JSObject *singleObject() const;
   266     /* Accessors for TypeObject types */
   268     bool isTypeObject() const {
   269         return isObject() && !(data & 1);
   270     }
   272     inline TypeObject *typeObject() const;
   274     bool operator == (Type o) const { return data == o.data; }
   275     bool operator != (Type o) const { return data != o.data; }
   277     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
   278     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
   279     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
   280     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
   281     static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
   282     static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
   283     static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
   284     static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
   285     static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
   287     static inline Type PrimitiveType(JSValueType type) {
   288         JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
   289         return Type(type);
   290     }
   292     static inline Type ObjectType(JSObject *obj);
   293     static inline Type ObjectType(TypeObject *obj);
   294     static inline Type ObjectType(TypeObjectKey *obj);
   295 };
   297 /* Get the type of a jsval, or zero for an unknown special value. */
   298 inline Type GetValueType(const Value &val);
   300 /*
   301  * Get the type of a possibly optimized out value. This generally only
   302  * happens on unconditional type monitors on bailing out of Ion, such as
   303  * for argument and local types.
   304  */
   305 inline Type GetMaybeOptimizedOutValueType(const Value &val);
   307 /*
   308  * Type inference memory management overview.
   309  *
   310  * Type information about the values observed within scripts and about the
   311  * contents of the heap is accumulated as the program executes. Compilation
   312  * accumulates constraints relating type information on the heap with the
   313  * compilations that should be invalidated when those types change. Type
   314  * information and constraints are allocated in the zone's typeLifoAlloc,
   315  * and on GC all data referring to live things is copied into a new allocator.
   316  * Thus, type set and constraints only hold weak references.
   317  */
   319 /*
   320  * A constraint which listens to additions to a type set and propagates those
   321  * changes to other type sets.
   322  */
   323 class TypeConstraint
   324 {
   325 public:
   326     /* Next constraint listening to the same type set. */
   327     TypeConstraint *next;
   329     TypeConstraint()
   330         : next(nullptr)
   331     {}
   333     /* Debugging name for this kind of constraint. */
   334     virtual const char *kind() = 0;
   336     /* Register a new type for the set this constraint is listening to. */
   337     virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
   339     /*
   340      * For constraints attached to an object property's type set, mark the
   341      * property as having its configuration changed.
   342      */
   343     virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
   345     /*
   346      * For constraints attached to the JSID_EMPTY type set on an object,
   347      * indicate a change in one of the object's dynamic property flags or other
   348      * state.
   349      */
   350     virtual void newObjectState(JSContext *cx, TypeObject *object) {}
   352     /*
   353      * If the data this constraint refers to is still live, copy it into the
   354      * zone's new allocator. Type constraints only hold weak references.
   355      */
   356     virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
   357 };
   359 /* Flags and other state stored in TypeSet::flags */
   360 enum MOZ_ENUM_TYPE(uint32_t) {
   361     TYPE_FLAG_UNDEFINED =  0x1,
   362     TYPE_FLAG_NULL      =  0x2,
   363     TYPE_FLAG_BOOLEAN   =  0x4,
   364     TYPE_FLAG_INT32     =  0x8,
   365     TYPE_FLAG_DOUBLE    = 0x10,
   366     TYPE_FLAG_STRING    = 0x20,
   367     TYPE_FLAG_LAZYARGS  = 0x40,
   368     TYPE_FLAG_ANYOBJECT = 0x80,
   370     /* Mask containing all primitives */
   371     TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
   372                           TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING,
   374     /* Mask/shift for the number of objects in objectSet */
   375     TYPE_FLAG_OBJECT_COUNT_MASK   = 0x1f00,
   376     TYPE_FLAG_OBJECT_COUNT_SHIFT  = 8,
   377     TYPE_FLAG_OBJECT_COUNT_LIMIT  =
   378         TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
   380     /* Whether the contents of this type set are totally unknown. */
   381     TYPE_FLAG_UNKNOWN             = 0x00002000,
   383     /* Mask of normal type flags on a type set. */
   384     TYPE_FLAG_BASE_MASK           = 0x000020ff,
   386     /* Additional flags for HeapTypeSet sets. */
   388     /*
   389      * Whether the property has ever been deleted or reconfigured to behave
   390      * differently from a plain data property, other than making the property
   391      * non-writable.
   392      */
   393     TYPE_FLAG_NON_DATA_PROPERTY = 0x00004000,
   395     /* Whether the property has ever been made non-writable. */
   396     TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00008000,
   398     /*
   399      * Whether the property is definitely in a particular slot on all objects
   400      * from which it has not been deleted or reconfigured. For singletons
   401      * this may be a fixed or dynamic slot, and for other objects this will be
   402      * a fixed slot.
   403      *
   404      * If the property is definite, mask and shift storing the slot + 1.
   405      * Otherwise these bits are clear.
   406      */
   407     TYPE_FLAG_DEFINITE_MASK       = 0xffff0000,
   408     TYPE_FLAG_DEFINITE_SHIFT      = 16
   409 };
   410 typedef uint32_t TypeFlags;
   412 /* Flags and other state stored in TypeObject::flags */
   413 enum MOZ_ENUM_TYPE(uint32_t) {
   414     /* Whether this type object is associated with some allocation site. */
   415     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
   417     /* If set, addendum information should not be installed on this object. */
   418     OBJECT_FLAG_ADDENDUM_CLEARED      = 0x2,
   420     /*
   421      * If set, the object's prototype might be in the nursery and can't be
   422      * used during Ion compilation (which may be occurring off thread).
   423      */
   424     OBJECT_FLAG_NURSERY_PROTO         = 0x4,
   426     /*
   427      * Whether we have ensured all type sets in the compartment contain
   428      * ANYOBJECT instead of this object.
   429      */
   430     OBJECT_FLAG_SETS_MARKED_UNKNOWN   = 0x8,
   432     /* Mask/shift for the number of properties in propertySet */
   433     OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff0,
   434     OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 4,
   435     OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
   436         OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
   438     /* Whether any objects this represents may have sparse indexes. */
   439     OBJECT_FLAG_SPARSE_INDEXES        = 0x00010000,
   441     /* Whether any objects this represents may not have packed dense elements. */
   442     OBJECT_FLAG_NON_PACKED            = 0x00020000,
   444     /*
   445      * Whether any objects this represents may be arrays whose length does not
   446      * fit in an int32.
   447      */
   448     OBJECT_FLAG_LENGTH_OVERFLOW       = 0x00040000,
   450     /* Whether any objects have been iterated over. */
   451     OBJECT_FLAG_ITERATED              = 0x00080000,
   453     /* For a global object, whether flags were set on the RegExpStatics. */
   454     OBJECT_FLAG_REGEXP_FLAGS_SET      = 0x00100000,
   456     /*
   457      * For the function on a run-once script, whether the function has actually
   458      * run multiple times.
   459      */
   460     OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
   462     /*
   463      * Whether objects with this type should be allocated directly in the
   464      * tenured heap.
   465      */
   466     OBJECT_FLAG_PRE_TENURE            = 0x00400000,
   468     /*
   469      * Whether all properties of this object are considered unknown.
   470      * If set, all other flags in DYNAMIC_MASK will also be set.
   471      */
   472     OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x00800000,
   474     /* Flags which indicate dynamic properties of represented objects. */
   475     OBJECT_FLAG_DYNAMIC_MASK          = 0x00ff0000,
   477     /* Mask for objects created with unknown properties. */
   478     OBJECT_FLAG_UNKNOWN_MASK =
   479         OBJECT_FLAG_DYNAMIC_MASK
   480       | OBJECT_FLAG_SETS_MARKED_UNKNOWN
   481 };
   482 typedef uint32_t TypeObjectFlags;
   484 class StackTypeSet;
   485 class HeapTypeSet;
   486 class TemporaryTypeSet;
   488 /*
   489  * Information about the set of types associated with an lvalue. There are
   490  * three kinds of type sets:
   491  *
   492  * - StackTypeSet are associated with TypeScripts, for arguments and values
   493  *   observed at property reads. These are implicitly frozen on compilation
   494  *   and do not have constraints attached to them.
   495  *
   496  * - HeapTypeSet are associated with the properties of TypeObjects. These
   497  *   may have constraints added to them to trigger invalidation of compiled
   498  *   code.
   499  *
   500  * - TemporaryTypeSet are created during compilation and do not outlive
   501  *   that compilation.
   502  */
   503 class TypeSet
   504 {
   505   protected:
   506     /* Flags for this type set. */
   507     TypeFlags flags;
   509     /* Possible objects this type set can represent. */
   510     TypeObjectKey **objectSet;
   512   public:
   514     TypeSet()
   515       : flags(0), objectSet(nullptr)
   516     {}
   518     void print();
   520     /* Whether this set contains a specific type. */
   521     inline bool hasType(Type type) const;
   523     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
   524     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
   525     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
   526     bool empty() const { return !baseFlags() && !baseObjectCount(); }
   528     bool hasAnyFlag(TypeFlags flags) const {
   529         JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
   530         return !!(baseFlags() & flags);
   531     }
   533     bool nonDataProperty() const {
   534         return flags & TYPE_FLAG_NON_DATA_PROPERTY;
   535     }
   536     bool nonWritableProperty() const {
   537         return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
   538     }
   539     bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
   540     unsigned definiteSlot() const {
   541         JS_ASSERT(definiteProperty());
   542         return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
   543     }
   545     /* Join two type sets into a new set. The result should not be modified further. */
   546     static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
   548     /* Add a type to this set using the specified allocator. */
   549     void addType(Type type, LifoAlloc *alloc);
   551     /* Get a list of all types in this set. */
   552     typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
   553     bool enumerateTypes(TypeList *list);
   555     /*
   556      * Iterate through the objects in this set. getObjectCount overapproximates
   557      * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
   558      * may return nullptr.
   559      */
   560     inline unsigned getObjectCount() const;
   561     inline TypeObjectKey *getObject(unsigned i) const;
   562     inline JSObject *getSingleObject(unsigned i) const;
   563     inline TypeObject *getTypeObject(unsigned i) const;
   565     /* The Class of an object in this set. */
   566     inline const Class *getObjectClass(unsigned i) const;
   568     bool canSetDefinite(unsigned slot) {
   569         // Note: the cast is required to work around an MSVC issue.
   570         return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
   571     }
   572     void setDefinite(unsigned slot) {
   573         JS_ASSERT(canSetDefinite(slot));
   574         flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
   575         JS_ASSERT(definiteSlot() == slot);
   576     }
   578     /* Whether any values in this set might have the specified type. */
   579     bool mightBeMIRType(jit::MIRType type);
   581     /*
   582      * Get whether this type set is known to be a subset of other.
   583      * This variant doesn't freeze constraints. That variant is called knownSubset
   584      */
   585     bool isSubset(TypeSet *other);
   587     /* Forward all types in this set to the specified constraint. */
   588     bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
   590     // Clone a type set into an arbitrary allocator.
   591     TemporaryTypeSet *clone(LifoAlloc *alloc) const;
   592     bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const;
   594     // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
   595     TemporaryTypeSet *filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const;
   597   protected:
   598     uint32_t baseObjectCount() const {
   599         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
   600     }
   601     inline void setBaseObjectCount(uint32_t count);
   603     void clearObjects();
   604 };
   606 /* Superclass common to stack and heap type sets. */
   607 class ConstraintTypeSet : public TypeSet
   608 {
   609   public:
   610     /* Chain of constraints which propagate changes out from this type set. */
   611     TypeConstraint *constraintList;
   613     ConstraintTypeSet() : constraintList(nullptr) {}
   615     /*
   616      * Add a type to this set, calling any constraint handlers if this is a new
   617      * possible type.
   618      */
   619     void addType(ExclusiveContext *cx, Type type);
   621     /* Add a new constraint to this set. */
   622     bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
   624     inline void sweep(JS::Zone *zone, bool *oom);
   625 };
   627 class StackTypeSet : public ConstraintTypeSet
   628 {
   629   public:
   630 };
   632 class HeapTypeSet : public ConstraintTypeSet
   633 {
   634     inline void newPropertyState(ExclusiveContext *cx);
   636   public:
   637     /* Mark this type set as representing a non-data property. */
   638     inline void setNonDataProperty(ExclusiveContext *cx);
   639     inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
   641     /* Mark this type set as representing a non-writable property. */
   642     inline void setNonWritableProperty(ExclusiveContext *cx);
   643 };
   645 class CompilerConstraintList;
   647 CompilerConstraintList *
   648 NewCompilerConstraintList(jit::TempAllocator &alloc);
   650 class TemporaryTypeSet : public TypeSet
   651 {
   652   public:
   653     TemporaryTypeSet() {}
   654     TemporaryTypeSet(Type type);
   656     TemporaryTypeSet(uint32_t flags, TypeObjectKey **objectSet) {
   657         this->flags = flags;
   658         this->objectSet = objectSet;
   659     }
   661     /*
   662      * Constraints for JIT compilation.
   663      *
   664      * Methods for JIT compilation. These must be used when a script is
   665      * currently being compiled (see AutoEnterCompilation) and will add
   666      * constraints ensuring that if the return value change in the future due
   667      * to new type information, the script's jitcode will be discarded.
   668      */
   670     /* Get any type tag which all values in this set must have. */
   671     jit::MIRType getKnownMIRType();
   673     bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
   675     /* Whether this value may be an object. */
   676     bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
   678     /*
   679      * Whether this typeset represents a potentially sentineled object value:
   680      * the value may be an object or null or undefined.
   681      * Returns false if the value cannot ever be an object.
   682      */
   683     bool objectOrSentinel() {
   684         TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
   685         if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
   686             return false;
   688         return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
   689     }
   691     /* Whether the type set contains objects with any of a set of flags. */
   692     bool hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
   694     /* Get the class shared by all objects in this set, or nullptr. */
   695     const Class *getKnownClass();
   697     /* Result returned from forAllClasses */
   698     enum ForAllResult {
   699         EMPTY=1,                // Set empty
   700         ALL_TRUE,               // Set not empty and predicate returned true for all classes
   701         ALL_FALSE,              // Set not empty and predicate returned false for all classes
   702         MIXED,                  // Set not empty and predicate returned false for some classes
   703                                 // and true for others, or set contains an unknown or non-object
   704                                 // type
   705     };
   707     /* Apply func to the members of the set and return an appropriate result.
   708      * The iteration may end early if the result becomes known early.
   709      */
   710     ForAllResult forAllClasses(bool (*func)(const Class *clasp));
   712     /* Get the prototype shared by all objects in this set, or nullptr. */
   713     JSObject *getCommonPrototype();
   715     /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */
   716     int getTypedArrayType();
   718     /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
   719     bool isDOMClass();
   721     /* Whether clasp->isCallable() is true for one or more objects in this set. */
   722     bool maybeCallable();
   724     /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
   725     bool maybeEmulatesUndefined();
   727     /* Get the single value which can appear in this type set, otherwise nullptr. */
   728     JSObject *getSingleton();
   730     /* Whether any objects in the type set needs a barrier on id. */
   731     bool propertyNeedsBarrier(CompilerConstraintList *constraints, jsid id);
   733     /*
   734      * Whether this set contains all types in other, except (possibly) the
   735      * specified type.
   736      */
   737     bool filtersType(const TemporaryTypeSet *other, Type type) const;
   739     enum DoubleConversion {
   740         /* All types in the set should use eager double conversion. */
   741         AlwaysConvertToDoubles,
   743         /* Some types in the set should use eager double conversion. */
   744         MaybeConvertToDoubles,
   746         /* No types should use eager double conversion. */
   747         DontConvertToDoubles,
   749         /* Some types should use eager double conversion, others cannot. */
   750         AmbiguousDoubleConversion
   751     };
   753     /*
   754      * Whether known double optimizations are possible for element accesses on
   755      * objects in this type set.
   756      */
   757     DoubleConversion convertDoubleElements(CompilerConstraintList *constraints);
   758 };
   760 bool
   761 AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id);
   763 bool
   764 AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
   765                                      JSScript *script, JSScript *calleeScript);
   767 /* Is this a reasonable PC to be doing inlining on? */
   768 inline bool isInlinableCall(jsbytecode *pc);
   770 /* Type information about a property. */
   771 struct Property
   772 {
   773     /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
   774     HeapId id;
   776     /* Possible types for this property, including types inherited from prototypes. */
   777     HeapTypeSet types;
   779     Property(jsid id)
   780       : id(id)
   781     {}
   783     Property(const Property &o)
   784       : id(o.id.get()), types(o.types)
   785     {}
   787     static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
   788     static jsid getKey(Property *p) { return p->id; }
   789 };
   791 struct TypeNewScript;
   792 struct TypeTypedObject;
   794 struct TypeObjectAddendum
   795 {
   796     enum Kind {
   797         NewScript,
   798         TypedObject
   799     };
   801     TypeObjectAddendum(Kind kind);
   803     const Kind kind;
   805     bool isNewScript() {
   806         return kind == NewScript;
   807     }
   809     TypeNewScript *asNewScript() {
   810         JS_ASSERT(isNewScript());
   811         return (TypeNewScript*) this;
   812     }
   814     bool isTypedObject() {
   815         return kind == TypedObject;
   816     }
   818     TypeTypedObject *asTypedObject() {
   819         JS_ASSERT(isTypedObject());
   820         return (TypeTypedObject*) this;
   821     }
   823     static inline void writeBarrierPre(TypeObjectAddendum *type);
   825     static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {}
   826 };
   828 /*
   829  * Information attached to a TypeObject if it is always constructed using 'new'
   830  * on a particular script. This is used to manage state related to the definite
   831  * properties on the type object: these definite properties depend on type
   832  * information which could change as the script executes (e.g. a scripted
   833  * setter is added to a prototype object), and we need to ensure both that the
   834  * appropriate type constraints are in place when necessary, and that we can
   835  * remove the definite property information and repair the JS stack if the
   836  * constraints are violated.
   837  */
   838 struct TypeNewScript : public TypeObjectAddendum
   839 {
   840     TypeNewScript();
   842     HeapPtrFunction fun;
   844     /*
   845      * Template object to use for newly constructed objects. Reflects all
   846      * definite properties the object will have and the allocation kind to use
   847      * for the object. The allocation kind --- and template object itself ---
   848      * is subject to change if objects allocated with this type are given
   849      * dynamic slots later on due to new properties being added after the
   850      * constructor function finishes.
   851      */
   852     HeapPtrObject templateObject;
   854     /*
   855      * Order in which properties become initialized. We need this in case a
   856      * scripted setter is added to one of the object's prototypes while it is
   857      * in the middle of being initialized, so we can walk the stack and fixup
   858      * any objects which look for in-progress objects which were prematurely
   859      * set with their final shape. Property assignments in inner frames are
   860      * preceded by a series of SETPROP_FRAME entries specifying the stack down
   861      * to the frame containing the write.
   862      */
   863     struct Initializer {
   864         enum Kind {
   865             SETPROP,
   866             SETPROP_FRAME,
   867             DONE
   868         } kind;
   869         uint32_t offset;
   870         Initializer(Kind kind, uint32_t offset)
   871           : kind(kind), offset(offset)
   872         {}
   873     };
   874     Initializer *initializerList;
   876     static inline void writeBarrierPre(TypeNewScript *newScript);
   877 };
   879 struct TypeTypedObject : public TypeObjectAddendum
   880 {
   881   private:
   882     HeapPtrObject descr_;
   884   public:
   885     TypeTypedObject(Handle<TypeDescr*> descr);
   887     HeapPtrObject &descrHeapPtr() {
   888         return descr_;
   889     }
   891     TypeDescr &descr();
   892 };
   894 /*
   895  * Lazy type objects overview.
   896  *
   897  * Type objects which represent at most one JS object are constructed lazily.
   898  * These include types for native functions, standard classes, scripted
   899  * functions defined at the top level of global/eval scripts, and in some
   900  * other cases. Typical web workloads often create many windows (and many
   901  * copies of standard natives) and many scripts, with comparatively few
   902  * non-singleton types.
   903  *
   904  * We can recover the type information for the object from examining it,
   905  * so don't normally track the possible types of its properties as it is
   906  * updated. Property type sets for the object are only constructed when an
   907  * analyzed script attaches constraints to it: the script is querying that
   908  * property off the object or another which delegates to it, and the analysis
   909  * information is sensitive to changes in the property's type. Future changes
   910  * to the property (whether those uncovered by analysis or those occurring
   911  * in the VM) will treat these properties like those of any other type object.
   912  */
   914 /* Type information about an object accessed by a script. */
   915 struct TypeObject : gc::BarrieredCell<TypeObject>
   916 {
   917   private:
   918     /* Class shared by object using this type. */
   919     const Class *clasp_;
   921     /* Prototype shared by objects using this type. */
   922     HeapPtrObject proto_;
   924     /*
   925      * Whether there is a singleton JS object with this type. That JS object
   926      * must appear in type sets instead of this; we include the back reference
   927      * here to allow reverting the JS object to a lazy type.
   928      */
   929     HeapPtrObject singleton_;
   931   public:
   933     const Class *clasp() const {
   934         return clasp_;
   935     }
   937     void setClasp(const Class *clasp) {
   938         JS_ASSERT(singleton());
   939         clasp_ = clasp;
   940     }
   942     TaggedProto proto() const {
   943         return TaggedProto(proto_);
   944     }
   946     JSObject *singleton() const {
   947         return singleton_;
   948     }
   950     // For use during marking, don't call otherwise.
   951     HeapPtrObject &protoRaw() { return proto_; }
   952     HeapPtrObject &singletonRaw() { return singleton_; }
   954     void setProto(JSContext *cx, TaggedProto proto);
   955     void setProtoUnchecked(TaggedProto proto) {
   956         proto_ = proto.raw();
   957     }
   959     void initSingleton(JSObject *singleton) {
   960         singleton_ = singleton;
   961     }
   963     /*
   964      * Value held by singleton if this is a standin type for a singleton JS
   965      * object whose type has not been constructed yet.
   966      */
   967     static const size_t LAZY_SINGLETON = 1;
   968     bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; }
   970   private:
   971     /* Flags for this object. */
   972     TypeObjectFlags flags_;
   974     /*
   975      * This field allows various special classes of objects to attach
   976      * additional information to a type object:
   977      *
   978      * - `TypeNewScript`: If addendum is a `TypeNewScript`, it
   979      *   indicates that objects of this type have always been
   980      *   constructed using 'new' on the specified script, which adds
   981      *   some number of properties to the object in a definite order
   982      *   before the object escapes.
   983      */
   984     HeapPtr<TypeObjectAddendum> addendum;
   985   public:
   987     TypeObjectFlags flags() const {
   988         return flags_;
   989     }
   991     void addFlags(TypeObjectFlags flags) {
   992         flags_ |= flags;
   993     }
   995     void clearFlags(TypeObjectFlags flags) {
   996         flags_ &= ~flags;
   997     }
   999     bool hasNewScript() const {
  1000         return addendum && addendum->isNewScript();
  1003     TypeNewScript *newScript() {
  1004         return addendum->asNewScript();
  1007     bool hasTypedObject() {
  1008         return addendum && addendum->isTypedObject();
  1011     TypeTypedObject *typedObject() {
  1012         return addendum->asTypedObject();
  1015     void setAddendum(TypeObjectAddendum *addendum);
  1017     /*
  1018      * Tag the type object for a binary data type descriptor, instance,
  1019      * or handle with the type representation of the data it points at.
  1020      * If this type object is already tagged with a binary data addendum,
  1021      * this addendum must already be associated with the same TypeRepresentation,
  1022      * and the method has no effect.
  1023      */
  1024     bool addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr);
  1026   private:
  1027     /*
  1028      * Properties of this object. This may contain JSID_VOID, representing the
  1029      * types of all integer indexes of the object, and/or JSID_EMPTY, holding
  1030      * constraints listening to changes to the object's state.
  1032      * The type sets in the properties of a type object describe the possible
  1033      * values that can be read out of that property in actual JS objects.
  1034      * Properties only account for native properties (those with a slot and no
  1035      * specialized getter hook) and the elements of dense arrays. For accesses
  1036      * on such properties, the correspondence is as follows:
  1038      * 1. If the type has unknownProperties(), the possible properties and
  1039      *    value types for associated JSObjects are unknown.
  1041      * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
  1042      *    which is a property in obj, before obj->getProperty(id) the property
  1043      *    in type for id must reflect the result of the getProperty.
  1045      *    There is an exception for properties of global JS objects which
  1046      *    are undefined at the point where the property was (lazily) generated.
  1047      *    In such cases the property type set will remain empty, and the
  1048      *    'undefined' type will only be added after a subsequent assignment or
  1049      *    deletion. After these properties have been assigned a defined value,
  1050      *    the only way they can become undefined again is after such an assign
  1051      *    or deletion.
  1053      *    There is another exception for array lengths, which are special cased
  1054      *    by the compiler and VM and are not reflected in property types.
  1056      * We establish these by using write barriers on calls to setProperty and
  1057      * defineProperty which are on native properties, and on any jitcode which
  1058      * might update the property with a new type.
  1059      */
  1060     Property **propertySet;
  1061   public:
  1063     /* If this is an interpreted function, the function object. */
  1064     HeapPtrFunction interpretedFunction;
  1066 #if JS_BITS_PER_WORD == 32
  1067     uint32_t padding;
  1068 #endif
  1070     inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags);
  1072     bool hasAnyFlags(TypeObjectFlags flags) {
  1073         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
  1074         return !!(this->flags() & flags);
  1076     bool hasAllFlags(TypeObjectFlags flags) {
  1077         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
  1078         return (this->flags() & flags) == flags;
  1081     bool unknownProperties() {
  1082         JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
  1083                      hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
  1084         return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
  1087     bool shouldPreTenure() {
  1088         return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
  1091     bool hasTenuredProto() const {
  1092         return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
  1095     gc::InitialHeap initialHeap(CompilerConstraintList *constraints);
  1097     bool canPreTenure() {
  1098         // Only types associated with particular allocation sites or 'new'
  1099         // scripts can be marked as needing pretenuring. Other types can be
  1100         // used for different purposes across the compartment and can't use
  1101         // this bit reliably.
  1102         if (unknownProperties())
  1103             return false;
  1104         return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
  1107     void setShouldPreTenure(ExclusiveContext *cx) {
  1108         JS_ASSERT(canPreTenure());
  1109         setFlags(cx, OBJECT_FLAG_PRE_TENURE);
  1112     /*
  1113      * Get or create a property of this object. Only call this for properties which
  1114      * a script accesses explicitly.
  1115      */
  1116     inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id);
  1118     /* Get a property only if it already exists. */
  1119     inline HeapTypeSet *maybeGetProperty(jsid id);
  1121     inline unsigned getPropertyCount();
  1122     inline Property *getProperty(unsigned i);
  1124     /* Helpers */
  1126     void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, HeapTypeSet *types);
  1127     bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj);
  1128     bool matchDefiniteProperties(HandleObject obj);
  1129     void addPrototype(JSContext *cx, TypeObject *proto);
  1130     void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
  1131     void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
  1132     void markPropertyNonData(ExclusiveContext *cx, jsid id);
  1133     void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
  1134     void markStateChange(ExclusiveContext *cx);
  1135     void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
  1136     void markUnknown(ExclusiveContext *cx);
  1137     void clearAddendum(ExclusiveContext *cx);
  1138     void clearNewScriptAddendum(ExclusiveContext *cx);
  1139     void clearTypedObjectAddendum(ExclusiveContext *cx);
  1140     void maybeClearNewScriptAddendumOnOOM();
  1141     bool isPropertyNonData(jsid id);
  1142     bool isPropertyNonWritable(jsid id);
  1144     void print();
  1146     inline void clearProperties();
  1147     inline void sweep(FreeOp *fop, bool *oom);
  1149     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
  1151     /*
  1152      * Type objects don't have explicit finalizers. Memory owned by a type
  1153      * object pending deletion is released when weak references are sweeped
  1154      * from all the compartment's type objects.
  1155      */
  1156     void finalize(FreeOp *fop) {}
  1158     static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
  1160     static inline uint32_t offsetOfClasp() {
  1161         return offsetof(TypeObject, clasp_);
  1164     static inline uint32_t offsetOfProto() {
  1165         return offsetof(TypeObject, proto_);
  1168   private:
  1169     inline uint32_t basePropertyCount() const;
  1170     inline void setBasePropertyCount(uint32_t count);
  1172     static void staticAsserts() {
  1173         JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
  1175 };
  1177 /*
  1178  * Entries for the per-compartment set of type objects which are 'new' types to
  1179  * use for some prototype and constructed with an optional script. This also
  1180  * includes entries for the set of lazy type objects in the compartment, which
  1181  * use a null script (though there are only a few of these per compartment).
  1182  */
  1183 struct TypeObjectWithNewScriptEntry
  1185     ReadBarriered<TypeObject> object;
  1187     // Note: This pointer is only used for equality and does not need a read barrier.
  1188     JSFunction *newFunction;
  1190     TypeObjectWithNewScriptEntry(TypeObject *object, JSFunction *newFunction)
  1191       : object(object), newFunction(newFunction)
  1192     {}
  1194     struct Lookup {
  1195         const Class *clasp;
  1196         TaggedProto hashProto;
  1197         TaggedProto matchProto;
  1198         JSFunction *newFunction;
  1200         Lookup(const Class *clasp, TaggedProto proto, JSFunction *newFunction)
  1201           : clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction)
  1202         {}
  1204 #ifdef JSGC_GENERATIONAL
  1205         /*
  1206          * For use by generational post barriers only.  Look up an entry whose
  1207          * proto has been moved, but was hashed with the original value.
  1208          */
  1209         Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction *newFunction)
  1210             : clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction)
  1211         {}
  1212 #endif
  1214     };
  1216     static inline HashNumber hash(const Lookup &lookup);
  1217     static inline bool match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup);
  1218     static void rekey(TypeObjectWithNewScriptEntry &k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; }
  1219 };
  1220 typedef HashSet<TypeObjectWithNewScriptEntry,
  1221                 TypeObjectWithNewScriptEntry,
  1222                 SystemAllocPolicy> TypeObjectWithNewScriptSet;
  1224 /* Whether to use a new type object when calling 'new' at script/pc. */
  1225 bool
  1226 UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
  1228 bool
  1229 UseNewTypeForClone(JSFunction *fun);
  1231 /*
  1232  * Whether Array.prototype, or an object on its proto chain, has an
  1233  * indexed property.
  1234  */
  1235 bool
  1236 ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSScript *script);
  1238 /* Whether obj or any of its prototypes have an indexed property. */
  1239 bool
  1240 TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, TemporaryTypeSet *types);
  1242 /* Persistent type information for a script, retained across GCs. */
  1243 class TypeScript
  1245     friend class ::JSScript;
  1247     // Variable-size array
  1248     StackTypeSet typeArray_[1];
  1250   public:
  1251     /* Array of type type sets for variables and JOF_TYPESET ops. */
  1252     StackTypeSet *typeArray() const {
  1253         // Ensure typeArray_ is the last data member of TypeScript.
  1254         JS_STATIC_ASSERT(sizeof(TypeScript) ==
  1255             sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
  1256         return const_cast<StackTypeSet *>(typeArray_);
  1259     static inline size_t SizeIncludingTypeArray(size_t arraySize) {
  1260         // Ensure typeArray_ is the last data member of TypeScript.
  1261         JS_STATIC_ASSERT(sizeof(TypeScript) ==
  1262             sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
  1263         return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
  1266     static inline unsigned NumTypeSets(JSScript *script);
  1268     static inline StackTypeSet *ThisTypes(JSScript *script);
  1269     static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i);
  1271     /* Get the type set for values observed at an opcode. */
  1272     static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc);
  1274     template <typename TYPESET>
  1275     static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap,
  1276                                          uint32_t *hint, TYPESET *typeArray);
  1278     /* Get a type object for an allocation site in this script. */
  1279     static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc,
  1280                                          JSProtoKey kind);
  1282     /*
  1283      * Monitor a bytecode pushing any value. This must be called for any opcode
  1284      * which is JOF_TYPESET, and where either the script has not been analyzed
  1285      * by type inference or where the pc has type barriers. For simplicity, we
  1286      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
  1287      * and only look at barriers when generating JIT code for the script.
  1288      */
  1289     static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
  1290                                const js::Value &val);
  1291     static inline void Monitor(JSContext *cx, const js::Value &rval);
  1293     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
  1294     static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id);
  1296     /* Add a type for a variable in a script. */
  1297     static inline void SetThis(JSContext *cx, JSScript *script, Type type);
  1298     static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
  1299     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
  1300     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg,
  1301                                    const js::Value &value);
  1303     /*
  1304      * Freeze all the stack type sets in a script, for a compilation. Returns
  1305      * copies of the type sets which will be checked against the actual ones
  1306      * under FinishCompilation, to detect any type changes.
  1307      */
  1308     static bool FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script,
  1309                                TemporaryTypeSet **pThisTypes,
  1310                                TemporaryTypeSet **pArgTypes,
  1311                                TemporaryTypeSet **pBytecodeTypes);
  1313     static void Purge(JSContext *cx, HandleScript script);
  1315     static void Sweep(FreeOp *fop, JSScript *script, bool *oom);
  1316     void destroy();
  1318     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  1319         return mallocSizeOf(this);
  1322 #ifdef DEBUG
  1323     void printTypes(JSContext *cx, HandleScript script) const;
  1324 #endif
  1325 };
  1327 void
  1328 FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap);
  1330 class RecompileInfo;
  1332 // Allocate a CompilerOutput for a finished compilation and generate the type
  1333 // constraints for the compilation. Returns whether the type constraints
  1334 // still hold.
  1335 bool
  1336 FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode executionMode,
  1337                   CompilerConstraintList *constraints, RecompileInfo *precompileInfo);
  1339 // Update the actual types in any scripts queried by constraints with any
  1340 // speculative types added during the definite properties analysis.
  1341 void
  1342 FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *constraints);
  1344 struct ArrayTableKey;
  1345 typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
  1347 struct ObjectTableKey;
  1348 struct ObjectTableEntry;
  1349 typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
  1351 struct AllocationSiteKey;
  1352 typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
  1354 class HeapTypeSetKey;
  1356 // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
  1357 struct TypeObjectKey
  1359     static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
  1360     static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
  1362     static TypeObjectKey *get(JSObject *obj) {
  1363         JS_ASSERT(obj);
  1364         return (TypeObjectKey *) (uintptr_t(obj) | 1);
  1366     static TypeObjectKey *get(TypeObject *obj) {
  1367         JS_ASSERT(obj);
  1368         return (TypeObjectKey *) obj;
  1371     bool isTypeObject() {
  1372         return (uintptr_t(this) & 1) == 0;
  1374     bool isSingleObject() {
  1375         return (uintptr_t(this) & 1) != 0;
  1378     TypeObject *asTypeObject() {
  1379         JS_ASSERT(isTypeObject());
  1380         return (TypeObject *) this;
  1382     JSObject *asSingleObject() {
  1383         JS_ASSERT(isSingleObject());
  1384         return (JSObject *) (uintptr_t(this) & ~1);
  1387     const Class *clasp();
  1388     TaggedProto proto();
  1389     bool hasTenuredProto();
  1390     JSObject *singleton();
  1391     TypeNewScript *newScript();
  1393     bool unknownProperties();
  1394     bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
  1395     void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
  1396     void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints);
  1397     void watchStateChangeForTypedArrayData(CompilerConstraintList *constraints);
  1398     HeapTypeSetKey property(jsid id);
  1399     void ensureTrackedProperty(JSContext *cx, jsid id);
  1401     TypeObject *maybeType();
  1402 };
  1404 // Representation of a heap type property which may or may not be instantiated.
  1405 // Heap properties for singleton types are instantiated lazily as they are used
  1406 // by the compiler, but this is only done on the main thread. If we are
  1407 // compiling off thread and use a property which has not yet been instantiated,
  1408 // it will be treated as empty and non-configured and will be instantiated when
  1409 // rejoining to the main thread. If it is in fact not empty, the compilation
  1410 // will fail; to avoid this, we try to instantiate singleton property types
  1411 // during generation of baseline caches.
  1412 class HeapTypeSetKey
  1414     friend class TypeObjectKey;
  1416     // Object and property being accessed.
  1417     TypeObjectKey *object_;
  1418     jsid id_;
  1420     // If instantiated, the underlying heap type set.
  1421     HeapTypeSet *maybeTypes_;
  1423   public:
  1424     HeapTypeSetKey()
  1425       : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
  1426     {}
  1428     TypeObjectKey *object() const { return object_; }
  1429     jsid id() const { return id_; }
  1430     HeapTypeSet *maybeTypes() const { return maybeTypes_; }
  1432     bool instantiate(JSContext *cx);
  1434     void freeze(CompilerConstraintList *constraints);
  1435     jit::MIRType knownMIRType(CompilerConstraintList *constraints);
  1436     bool nonData(CompilerConstraintList *constraints);
  1437     bool nonWritable(CompilerConstraintList *constraints);
  1438     bool isOwnProperty(CompilerConstraintList *constraints);
  1439     bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
  1440     JSObject *singleton(CompilerConstraintList *constraints);
  1441     bool needsBarrier(CompilerConstraintList *constraints);
  1442 };
  1444 /*
  1445  * Information about the result of the compilation of a script.  This structure
  1446  * stored in the TypeCompartment is indexed by the RecompileInfo. This
  1447  * indirection enables the invalidation of all constraints related to the same
  1448  * compilation.
  1449  */
  1450 class CompilerOutput
  1452     // If this compilation has not been invalidated, the associated script and
  1453     // kind of compilation being performed.
  1454     JSScript *script_;
  1455     ExecutionMode mode_ : 2;
  1457     // Whether this compilation is about to be invalidated.
  1458     bool pendingInvalidation_ : 1;
  1460     // During sweeping, the list of compiler outputs is compacted and invalidated
  1461     // outputs are removed. This gives the new index for a valid compiler output.
  1462     uint32_t sweepIndex_ : 29;
  1464   public:
  1465     static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1;
  1467     CompilerOutput()
  1468       : script_(nullptr), mode_(SequentialExecution),
  1469         pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
  1470     {}
  1472     CompilerOutput(JSScript *script, ExecutionMode mode)
  1473       : script_(script), mode_(mode),
  1474         pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
  1475     {}
  1477     JSScript *script() const { return script_; }
  1478     inline ExecutionMode mode() const { return mode_; }
  1480     inline jit::IonScript *ion() const;
  1482     bool isValid() const {
  1483         return script_ != nullptr;
  1485     void invalidate() {
  1486         script_ = nullptr;
  1489     void setPendingInvalidation() {
  1490         pendingInvalidation_ = true;
  1492     bool pendingInvalidation() {
  1493         return pendingInvalidation_;
  1496     void setSweepIndex(uint32_t index) {
  1497         if (index >= INVALID_SWEEP_INDEX)
  1498             MOZ_CRASH();
  1499         sweepIndex_ = index;
  1501     void invalidateSweepIndex() {
  1502         sweepIndex_ = INVALID_SWEEP_INDEX;
  1504     uint32_t sweepIndex() {
  1505         JS_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
  1506         return sweepIndex_;
  1508 };
  1510 class RecompileInfo
  1512     uint32_t outputIndex;
  1514   public:
  1515     RecompileInfo(uint32_t outputIndex = uint32_t(-1))
  1516       : outputIndex(outputIndex)
  1517     {}
  1519     bool operator == (const RecompileInfo &o) const {
  1520         return outputIndex == o.outputIndex;
  1522     CompilerOutput *compilerOutput(TypeZone &types) const;
  1523     CompilerOutput *compilerOutput(JSContext *cx) const;
  1524     bool shouldSweep(TypeZone &types);
  1525 };
  1527 /* Type information for a compartment. */
  1528 struct TypeCompartment
  1530     /* Constraint solving worklist structures. */
  1532     /* Number of scripts in this compartment. */
  1533     unsigned scriptCount;
  1535     /* Table for referencing types of objects keyed to an allocation site. */
  1536     AllocationSiteTable *allocationSiteTable;
  1538     /* Tables for determining types of singleton/JSON objects. */
  1540     ArrayTypeTable *arrayTypeTable;
  1541     ObjectTypeTable *objectTypeTable;
  1543   private:
  1544     void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type);
  1546   public:
  1547     void fixArrayType(ExclusiveContext *cx, JSObject *obj);
  1548     void fixObjectType(ExclusiveContext *cx, JSObject *obj);
  1549     void fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj);
  1551     JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties);
  1553     TypeCompartment();
  1554     ~TypeCompartment();
  1556     inline JSCompartment *compartment();
  1558     /* Prints results of this compartment if spew is enabled or force is set. */
  1559     void print(JSContext *cx, bool force);
  1561     /*
  1562      * Make a function or non-function object associated with an optional
  1563      * script. The 'key' parameter here may be an array, typed array, function
  1564      * or JSProto_Object to indicate a type whose class is unknown (not just
  1565      * js_ObjectClass).
  1566      */
  1567     TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
  1568                               TypeObjectFlags initialFlags = 0);
  1570     /* Get or make an object for an allocation site, and add to the allocation site table. */
  1571     TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
  1573     /* Mark any type set containing obj as having a generic object type. */
  1574     void markSetsUnknown(JSContext *cx, TypeObject *obj);
  1576     void clearTables();
  1577     void sweep(FreeOp *fop);
  1578     void finalizeObjects();
  1580     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
  1581                                 size_t *allocationSiteTables,
  1582                                 size_t *arrayTypeTables,
  1583                                 size_t *objectTypeTables);
  1584 };
  1586 void FixRestArgumentsType(ExclusiveContext *cxArg, JSObject *obj);
  1588 struct TypeZone
  1590     JS::Zone                     *zone_;
  1592     /* Pool for type information in this zone. */
  1593     static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
  1594     js::LifoAlloc                typeLifoAlloc;
  1596     /*
  1597      * All Ion compilations that have occured in this zone, for indexing via
  1598      * RecompileInfo. This includes both valid and invalid compilations, though
  1599      * invalidated compilations are swept on GC.
  1600      */
  1601     Vector<CompilerOutput> *compilerOutputs;
  1603     /* Pending recompilations to perform before execution of JIT code can resume. */
  1604     Vector<RecompileInfo> *pendingRecompiles;
  1606     TypeZone(JS::Zone *zone);
  1607     ~TypeZone();
  1609     JS::Zone *zone() const { return zone_; }
  1611     void sweep(FreeOp *fop, bool releaseTypes, bool *oom);
  1612     void clearAllNewScriptAddendumsOnOOM();
  1614     /* Mark a script as needing recompilation once inference has finished. */
  1615     void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
  1616     void addPendingRecompile(JSContext *cx, JSScript *script);
  1618     void processPendingRecompiles(FreeOp *fop);
  1619 };
  1621 enum SpewChannel {
  1622     ISpewOps,      /* ops: New constraints and types. */
  1623     ISpewResult,   /* result: Final type sets. */
  1624     SPEW_COUNT
  1625 };
  1627 #ifdef DEBUG
  1629 const char * InferSpewColorReset();
  1630 const char * InferSpewColor(TypeConstraint *constraint);
  1631 const char * InferSpewColor(TypeSet *types);
  1633 void InferSpew(SpewChannel which, const char *fmt, ...);
  1634 const char * TypeString(Type type);
  1635 const char * TypeObjectString(TypeObject *type);
  1637 /* Check that the type property for id in obj contains value. */
  1638 bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
  1640 #else
  1642 inline const char * InferSpewColorReset() { return nullptr; }
  1643 inline const char * InferSpewColor(TypeConstraint *constraint) { return nullptr; }
  1644 inline const char * InferSpewColor(TypeSet *types) { return nullptr; }
  1645 inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
  1646 inline const char * TypeString(Type type) { return nullptr; }
  1647 inline const char * TypeObjectString(TypeObject *type) { return nullptr; }
  1649 #endif
  1651 /* Print a warning, dump state and abort the program. */
  1652 MOZ_NORETURN void TypeFailure(JSContext *cx, const char *fmt, ...);
  1654 } /* namespace types */
  1655 } /* namespace js */
  1657 #endif /* jsinfer_h */

mercurial