js/src/jsinfer.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsinfer.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1657 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Definitions related to javascript type inference. */
    1.11 +
    1.12 +#ifndef jsinfer_h
    1.13 +#define jsinfer_h
    1.14 +
    1.15 +#include "mozilla/MemoryReporting.h"
    1.16 +#include "mozilla/TypedEnum.h"
    1.17 +
    1.18 +#include "jsalloc.h"
    1.19 +#include "jsfriendapi.h"
    1.20 +#include "jstypes.h"
    1.21 +
    1.22 +#include "ds/IdValuePair.h"
    1.23 +#include "ds/LifoAlloc.h"
    1.24 +#include "gc/Barrier.h"
    1.25 +#include "gc/Marking.h"
    1.26 +#include "jit/IonTypes.h"
    1.27 +#include "js/Utility.h"
    1.28 +#include "js/Vector.h"
    1.29 +
    1.30 +namespace js {
    1.31 +
    1.32 +class TypeDescr;
    1.33 +
    1.34 +class TaggedProto
    1.35 +{
    1.36 +  public:
    1.37 +    static JSObject * const LazyProto;
    1.38 +
    1.39 +    TaggedProto() : proto(nullptr) {}
    1.40 +    TaggedProto(JSObject *proto) : proto(proto) {}
    1.41 +
    1.42 +    uintptr_t toWord() const { return uintptr_t(proto); }
    1.43 +
    1.44 +    bool isLazy() const {
    1.45 +        return proto == LazyProto;
    1.46 +    }
    1.47 +    bool isObject() const {
    1.48 +        /* Skip nullptr and LazyProto. */
    1.49 +        return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
    1.50 +    }
    1.51 +    JSObject *toObject() const {
    1.52 +        JS_ASSERT(isObject());
    1.53 +        return proto;
    1.54 +    }
    1.55 +    JSObject *toObjectOrNull() const {
    1.56 +        JS_ASSERT(!proto || isObject());
    1.57 +        return proto;
    1.58 +    }
    1.59 +    JSObject *raw() const { return proto; }
    1.60 +
    1.61 +    bool operator ==(const TaggedProto &other) { return proto == other.proto; }
    1.62 +    bool operator !=(const TaggedProto &other) { return proto != other.proto; }
    1.63 +
    1.64 +  private:
    1.65 +    JSObject *proto;
    1.66 +};
    1.67 +
    1.68 +template <>
    1.69 +struct RootKind<TaggedProto>
    1.70 +{
    1.71 +    static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
    1.72 +};
    1.73 +
    1.74 +template <> struct GCMethods<const TaggedProto>
    1.75 +{
    1.76 +    static TaggedProto initial() { return TaggedProto(); }
    1.77 +    static ThingRootKind kind() { return THING_ROOT_OBJECT; }
    1.78 +    static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
    1.79 +};
    1.80 +
    1.81 +template <> struct GCMethods<TaggedProto>
    1.82 +{
    1.83 +    static TaggedProto initial() { return TaggedProto(); }
    1.84 +    static ThingRootKind kind() { return THING_ROOT_OBJECT; }
    1.85 +    static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
    1.86 +};
    1.87 +
    1.88 +template<class Outer>
    1.89 +class TaggedProtoOperations
    1.90 +{
    1.91 +    const TaggedProto *value() const {
    1.92 +        return static_cast<const Outer*>(this)->extract();
    1.93 +    }
    1.94 +
    1.95 +  public:
    1.96 +    uintptr_t toWord() const { return value()->toWord(); }
    1.97 +    inline bool isLazy() const { return value()->isLazy(); }
    1.98 +    inline bool isObject() const { return value()->isObject(); }
    1.99 +    inline JSObject *toObject() const { return value()->toObject(); }
   1.100 +    inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
   1.101 +    JSObject *raw() const { return value()->raw(); }
   1.102 +};
   1.103 +
   1.104 +template <>
   1.105 +class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> >
   1.106 +{
   1.107 +    friend class TaggedProtoOperations<Handle<TaggedProto> >;
   1.108 +    const TaggedProto * extract() const {
   1.109 +        return static_cast<const Handle<TaggedProto>*>(this)->address();
   1.110 +    }
   1.111 +};
   1.112 +
   1.113 +template <>
   1.114 +class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> >
   1.115 +{
   1.116 +    friend class TaggedProtoOperations<Rooted<TaggedProto> >;
   1.117 +    const TaggedProto *extract() const {
   1.118 +        return static_cast<const Rooted<TaggedProto> *>(this)->address();
   1.119 +    }
   1.120 +};
   1.121 +
   1.122 +class CallObject;
   1.123 +
   1.124 +/*
   1.125 + * Execution Mode Overview
   1.126 + *
   1.127 + * JavaScript code can execute either sequentially or in parallel, such as in
   1.128 + * PJS. Functions which behave identically in either execution mode can take a
   1.129 + * ThreadSafeContext, and functions which have similar but not identical
   1.130 + * behavior between execution modes can be templated on the mode. Such
   1.131 + * functions use a context parameter type from ExecutionModeTraits below
   1.132 + * indicating whether they are only permitted constrained operations (such as
   1.133 + * thread safety, and side effects limited to being thread-local), or whether
   1.134 + * they can have arbitrary side effects.
   1.135 + */
   1.136 +
   1.137 +enum ExecutionMode {
   1.138 +    /* Normal JavaScript execution. */
   1.139 +    SequentialExecution,
   1.140 +
   1.141 +    /*
   1.142 +     * JavaScript code to be executed in parallel worker threads in PJS in a
   1.143 +     * fork join fashion.
   1.144 +     */
   1.145 +    ParallelExecution,
   1.146 +
   1.147 +    /*
   1.148 +     * Modes after this point are internal and are not counted in
   1.149 +     * NumExecutionModes below.
   1.150 +     */
   1.151 +
   1.152 +    /*
   1.153 +     * MIR analysis performed when invoking 'new' on a script, to determine
   1.154 +     * definite properties. Used by the optimizing JIT.
   1.155 +     */
   1.156 +    DefinitePropertiesAnalysis,
   1.157 +
   1.158 +    /*
   1.159 +     * MIR analysis performed when executing a script which uses its arguments,
   1.160 +     * when it is not known whether a lazy arguments value can be used.
   1.161 +     */
   1.162 +    ArgumentsUsageAnalysis
   1.163 +};
   1.164 +
   1.165 +/*
   1.166 + * Not as part of the enum so we don't get warnings about unhandled enum
   1.167 + * values.
   1.168 + */
   1.169 +static const unsigned NumExecutionModes = ParallelExecution + 1;
   1.170 +
   1.171 +template <ExecutionMode mode>
   1.172 +struct ExecutionModeTraits
   1.173 +{
   1.174 +};
   1.175 +
   1.176 +template <> struct ExecutionModeTraits<SequentialExecution>
   1.177 +{
   1.178 +    typedef JSContext * ContextType;
   1.179 +    typedef ExclusiveContext * ExclusiveContextType;
   1.180 +
   1.181 +    static inline JSContext *toContextType(ExclusiveContext *cx);
   1.182 +};
   1.183 +
   1.184 +template <> struct ExecutionModeTraits<ParallelExecution>
   1.185 +{
   1.186 +    typedef ForkJoinContext * ContextType;
   1.187 +    typedef ForkJoinContext * ExclusiveContextType;
   1.188 +
   1.189 +    static inline ForkJoinContext *toContextType(ForkJoinContext *cx) { return cx; }
   1.190 +};
   1.191 +
   1.192 +namespace jit {
   1.193 +    struct IonScript;
   1.194 +    class IonAllocPolicy;
   1.195 +    class TempAllocator;
   1.196 +}
   1.197 +
   1.198 +namespace types {
   1.199 +
   1.200 +class TypeZone;
   1.201 +class TypeSet;
   1.202 +class TypeObjectKey;
   1.203 +
   1.204 +/*
   1.205 + * Information about a single concrete type. We pack this into a single word,
   1.206 + * where small values are particular primitive or other singleton types, and
   1.207 + * larger values are either specific JS objects or type objects.
   1.208 + */
   1.209 +class Type
   1.210 +{
   1.211 +    uintptr_t data;
   1.212 +    Type(uintptr_t data) : data(data) {}
   1.213 +
   1.214 +  public:
   1.215 +
   1.216 +    uintptr_t raw() const { return data; }
   1.217 +
   1.218 +    bool isPrimitive() const {
   1.219 +        return data < JSVAL_TYPE_OBJECT;
   1.220 +    }
   1.221 +
   1.222 +    bool isPrimitive(JSValueType type) const {
   1.223 +        JS_ASSERT(type < JSVAL_TYPE_OBJECT);
   1.224 +        return (uintptr_t) type == data;
   1.225 +    }
   1.226 +
   1.227 +    JSValueType primitive() const {
   1.228 +        JS_ASSERT(isPrimitive());
   1.229 +        return (JSValueType) data;
   1.230 +    }
   1.231 +
   1.232 +    bool isMagicArguments() const {
   1.233 +        return primitive() == JSVAL_TYPE_MAGIC;
   1.234 +    }
   1.235 +
   1.236 +    bool isSomeObject() const {
   1.237 +        return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
   1.238 +    }
   1.239 +
   1.240 +    bool isAnyObject() const {
   1.241 +        return data == JSVAL_TYPE_OBJECT;
   1.242 +    }
   1.243 +
   1.244 +    bool isUnknown() const {
   1.245 +        return data == JSVAL_TYPE_UNKNOWN;
   1.246 +    }
   1.247 +
   1.248 +    /* Accessors for types that are either JSObject or TypeObject. */
   1.249 +
   1.250 +    bool isObject() const {
   1.251 +        JS_ASSERT(!isAnyObject() && !isUnknown());
   1.252 +        return data > JSVAL_TYPE_UNKNOWN;
   1.253 +    }
   1.254 +
   1.255 +    bool isObjectUnchecked() const {
   1.256 +        return data > JSVAL_TYPE_UNKNOWN;
   1.257 +    }
   1.258 +
   1.259 +    inline TypeObjectKey *objectKey() const;
   1.260 +
   1.261 +    /* Accessors for JSObject types */
   1.262 +
   1.263 +    bool isSingleObject() const {
   1.264 +        return isObject() && !!(data & 1);
   1.265 +    }
   1.266 +
   1.267 +    inline JSObject *singleObject() const;
   1.268 +
   1.269 +    /* Accessors for TypeObject types */
   1.270 +
   1.271 +    bool isTypeObject() const {
   1.272 +        return isObject() && !(data & 1);
   1.273 +    }
   1.274 +
   1.275 +    inline TypeObject *typeObject() const;
   1.276 +
   1.277 +    bool operator == (Type o) const { return data == o.data; }
   1.278 +    bool operator != (Type o) const { return data != o.data; }
   1.279 +
   1.280 +    static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
   1.281 +    static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
   1.282 +    static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
   1.283 +    static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
   1.284 +    static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
   1.285 +    static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
   1.286 +    static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
   1.287 +    static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
   1.288 +    static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
   1.289 +
   1.290 +    static inline Type PrimitiveType(JSValueType type) {
   1.291 +        JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
   1.292 +        return Type(type);
   1.293 +    }
   1.294 +
   1.295 +    static inline Type ObjectType(JSObject *obj);
   1.296 +    static inline Type ObjectType(TypeObject *obj);
   1.297 +    static inline Type ObjectType(TypeObjectKey *obj);
   1.298 +};
   1.299 +
   1.300 +/* Get the type of a jsval, or zero for an unknown special value. */
   1.301 +inline Type GetValueType(const Value &val);
   1.302 +
   1.303 +/*
   1.304 + * Get the type of a possibly optimized out value. This generally only
   1.305 + * happens on unconditional type monitors on bailing out of Ion, such as
   1.306 + * for argument and local types.
   1.307 + */
   1.308 +inline Type GetMaybeOptimizedOutValueType(const Value &val);
   1.309 +
   1.310 +/*
   1.311 + * Type inference memory management overview.
   1.312 + *
   1.313 + * Type information about the values observed within scripts and about the
   1.314 + * contents of the heap is accumulated as the program executes. Compilation
   1.315 + * accumulates constraints relating type information on the heap with the
   1.316 + * compilations that should be invalidated when those types change. Type
   1.317 + * information and constraints are allocated in the zone's typeLifoAlloc,
   1.318 + * and on GC all data referring to live things is copied into a new allocator.
   1.319 + * Thus, type set and constraints only hold weak references.
   1.320 + */
   1.321 +
   1.322 +/*
   1.323 + * A constraint which listens to additions to a type set and propagates those
   1.324 + * changes to other type sets.
   1.325 + */
   1.326 +class TypeConstraint
   1.327 +{
   1.328 +public:
   1.329 +    /* Next constraint listening to the same type set. */
   1.330 +    TypeConstraint *next;
   1.331 +
   1.332 +    TypeConstraint()
   1.333 +        : next(nullptr)
   1.334 +    {}
   1.335 +
   1.336 +    /* Debugging name for this kind of constraint. */
   1.337 +    virtual const char *kind() = 0;
   1.338 +
   1.339 +    /* Register a new type for the set this constraint is listening to. */
   1.340 +    virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
   1.341 +
   1.342 +    /*
   1.343 +     * For constraints attached to an object property's type set, mark the
   1.344 +     * property as having its configuration changed.
   1.345 +     */
   1.346 +    virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
   1.347 +
   1.348 +    /*
   1.349 +     * For constraints attached to the JSID_EMPTY type set on an object,
   1.350 +     * indicate a change in one of the object's dynamic property flags or other
   1.351 +     * state.
   1.352 +     */
   1.353 +    virtual void newObjectState(JSContext *cx, TypeObject *object) {}
   1.354 +
   1.355 +    /*
   1.356 +     * If the data this constraint refers to is still live, copy it into the
   1.357 +     * zone's new allocator. Type constraints only hold weak references.
   1.358 +     */
   1.359 +    virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
   1.360 +};
   1.361 +
   1.362 +/* Flags and other state stored in TypeSet::flags */
   1.363 +enum MOZ_ENUM_TYPE(uint32_t) {
   1.364 +    TYPE_FLAG_UNDEFINED =  0x1,
   1.365 +    TYPE_FLAG_NULL      =  0x2,
   1.366 +    TYPE_FLAG_BOOLEAN   =  0x4,
   1.367 +    TYPE_FLAG_INT32     =  0x8,
   1.368 +    TYPE_FLAG_DOUBLE    = 0x10,
   1.369 +    TYPE_FLAG_STRING    = 0x20,
   1.370 +    TYPE_FLAG_LAZYARGS  = 0x40,
   1.371 +    TYPE_FLAG_ANYOBJECT = 0x80,
   1.372 +
   1.373 +    /* Mask containing all primitives */
   1.374 +    TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
   1.375 +                          TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING,
   1.376 +
   1.377 +    /* Mask/shift for the number of objects in objectSet */
   1.378 +    TYPE_FLAG_OBJECT_COUNT_MASK   = 0x1f00,
   1.379 +    TYPE_FLAG_OBJECT_COUNT_SHIFT  = 8,
   1.380 +    TYPE_FLAG_OBJECT_COUNT_LIMIT  =
   1.381 +        TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
   1.382 +
   1.383 +    /* Whether the contents of this type set are totally unknown. */
   1.384 +    TYPE_FLAG_UNKNOWN             = 0x00002000,
   1.385 +
   1.386 +    /* Mask of normal type flags on a type set. */
   1.387 +    TYPE_FLAG_BASE_MASK           = 0x000020ff,
   1.388 +
   1.389 +    /* Additional flags for HeapTypeSet sets. */
   1.390 +
   1.391 +    /*
   1.392 +     * Whether the property has ever been deleted or reconfigured to behave
   1.393 +     * differently from a plain data property, other than making the property
   1.394 +     * non-writable.
   1.395 +     */
   1.396 +    TYPE_FLAG_NON_DATA_PROPERTY = 0x00004000,
   1.397 +
   1.398 +    /* Whether the property has ever been made non-writable. */
   1.399 +    TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00008000,
   1.400 +
   1.401 +    /*
   1.402 +     * Whether the property is definitely in a particular slot on all objects
   1.403 +     * from which it has not been deleted or reconfigured. For singletons
   1.404 +     * this may be a fixed or dynamic slot, and for other objects this will be
   1.405 +     * a fixed slot.
   1.406 +     *
   1.407 +     * If the property is definite, mask and shift storing the slot + 1.
   1.408 +     * Otherwise these bits are clear.
   1.409 +     */
   1.410 +    TYPE_FLAG_DEFINITE_MASK       = 0xffff0000,
   1.411 +    TYPE_FLAG_DEFINITE_SHIFT      = 16
   1.412 +};
   1.413 +typedef uint32_t TypeFlags;
   1.414 +
   1.415 +/* Flags and other state stored in TypeObject::flags */
   1.416 +enum MOZ_ENUM_TYPE(uint32_t) {
   1.417 +    /* Whether this type object is associated with some allocation site. */
   1.418 +    OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
   1.419 +
   1.420 +    /* If set, addendum information should not be installed on this object. */
   1.421 +    OBJECT_FLAG_ADDENDUM_CLEARED      = 0x2,
   1.422 +
   1.423 +    /*
   1.424 +     * If set, the object's prototype might be in the nursery and can't be
   1.425 +     * used during Ion compilation (which may be occurring off thread).
   1.426 +     */
   1.427 +    OBJECT_FLAG_NURSERY_PROTO         = 0x4,
   1.428 +
   1.429 +    /*
   1.430 +     * Whether we have ensured all type sets in the compartment contain
   1.431 +     * ANYOBJECT instead of this object.
   1.432 +     */
   1.433 +    OBJECT_FLAG_SETS_MARKED_UNKNOWN   = 0x8,
   1.434 +
   1.435 +    /* Mask/shift for the number of properties in propertySet */
   1.436 +    OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff0,
   1.437 +    OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 4,
   1.438 +    OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
   1.439 +        OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
   1.440 +
   1.441 +    /* Whether any objects this represents may have sparse indexes. */
   1.442 +    OBJECT_FLAG_SPARSE_INDEXES        = 0x00010000,
   1.443 +
   1.444 +    /* Whether any objects this represents may not have packed dense elements. */
   1.445 +    OBJECT_FLAG_NON_PACKED            = 0x00020000,
   1.446 +
   1.447 +    /*
   1.448 +     * Whether any objects this represents may be arrays whose length does not
   1.449 +     * fit in an int32.
   1.450 +     */
   1.451 +    OBJECT_FLAG_LENGTH_OVERFLOW       = 0x00040000,
   1.452 +
   1.453 +    /* Whether any objects have been iterated over. */
   1.454 +    OBJECT_FLAG_ITERATED              = 0x00080000,
   1.455 +
   1.456 +    /* For a global object, whether flags were set on the RegExpStatics. */
   1.457 +    OBJECT_FLAG_REGEXP_FLAGS_SET      = 0x00100000,
   1.458 +
   1.459 +    /*
   1.460 +     * For the function on a run-once script, whether the function has actually
   1.461 +     * run multiple times.
   1.462 +     */
   1.463 +    OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
   1.464 +
   1.465 +    /*
   1.466 +     * Whether objects with this type should be allocated directly in the
   1.467 +     * tenured heap.
   1.468 +     */
   1.469 +    OBJECT_FLAG_PRE_TENURE            = 0x00400000,
   1.470 +
   1.471 +    /*
   1.472 +     * Whether all properties of this object are considered unknown.
   1.473 +     * If set, all other flags in DYNAMIC_MASK will also be set.
   1.474 +     */
   1.475 +    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x00800000,
   1.476 +
   1.477 +    /* Flags which indicate dynamic properties of represented objects. */
   1.478 +    OBJECT_FLAG_DYNAMIC_MASK          = 0x00ff0000,
   1.479 +
   1.480 +    /* Mask for objects created with unknown properties. */
   1.481 +    OBJECT_FLAG_UNKNOWN_MASK =
   1.482 +        OBJECT_FLAG_DYNAMIC_MASK
   1.483 +      | OBJECT_FLAG_SETS_MARKED_UNKNOWN
   1.484 +};
   1.485 +typedef uint32_t TypeObjectFlags;
   1.486 +
   1.487 +class StackTypeSet;
   1.488 +class HeapTypeSet;
   1.489 +class TemporaryTypeSet;
   1.490 +
   1.491 +/*
   1.492 + * Information about the set of types associated with an lvalue. There are
   1.493 + * three kinds of type sets:
   1.494 + *
   1.495 + * - StackTypeSet are associated with TypeScripts, for arguments and values
   1.496 + *   observed at property reads. These are implicitly frozen on compilation
   1.497 + *   and do not have constraints attached to them.
   1.498 + *
   1.499 + * - HeapTypeSet are associated with the properties of TypeObjects. These
   1.500 + *   may have constraints added to them to trigger invalidation of compiled
   1.501 + *   code.
   1.502 + *
   1.503 + * - TemporaryTypeSet are created during compilation and do not outlive
   1.504 + *   that compilation.
   1.505 + */
   1.506 +class TypeSet
   1.507 +{
   1.508 +  protected:
   1.509 +    /* Flags for this type set. */
   1.510 +    TypeFlags flags;
   1.511 +
   1.512 +    /* Possible objects this type set can represent. */
   1.513 +    TypeObjectKey **objectSet;
   1.514 +
   1.515 +  public:
   1.516 +
   1.517 +    TypeSet()
   1.518 +      : flags(0), objectSet(nullptr)
   1.519 +    {}
   1.520 +
   1.521 +    void print();
   1.522 +
   1.523 +    /* Whether this set contains a specific type. */
   1.524 +    inline bool hasType(Type type) const;
   1.525 +
   1.526 +    TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
   1.527 +    bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
   1.528 +    bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
   1.529 +    bool empty() const { return !baseFlags() && !baseObjectCount(); }
   1.530 +
   1.531 +    bool hasAnyFlag(TypeFlags flags) const {
   1.532 +        JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
   1.533 +        return !!(baseFlags() & flags);
   1.534 +    }
   1.535 +
   1.536 +    bool nonDataProperty() const {
   1.537 +        return flags & TYPE_FLAG_NON_DATA_PROPERTY;
   1.538 +    }
   1.539 +    bool nonWritableProperty() const {
   1.540 +        return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
   1.541 +    }
   1.542 +    bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
   1.543 +    unsigned definiteSlot() const {
   1.544 +        JS_ASSERT(definiteProperty());
   1.545 +        return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
   1.546 +    }
   1.547 +
   1.548 +    /* Join two type sets into a new set. The result should not be modified further. */
   1.549 +    static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
   1.550 +
   1.551 +    /* Add a type to this set using the specified allocator. */
   1.552 +    void addType(Type type, LifoAlloc *alloc);
   1.553 +
   1.554 +    /* Get a list of all types in this set. */
   1.555 +    typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
   1.556 +    bool enumerateTypes(TypeList *list);
   1.557 +
   1.558 +    /*
   1.559 +     * Iterate through the objects in this set. getObjectCount overapproximates
   1.560 +     * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
   1.561 +     * may return nullptr.
   1.562 +     */
   1.563 +    inline unsigned getObjectCount() const;
   1.564 +    inline TypeObjectKey *getObject(unsigned i) const;
   1.565 +    inline JSObject *getSingleObject(unsigned i) const;
   1.566 +    inline TypeObject *getTypeObject(unsigned i) const;
   1.567 +
   1.568 +    /* The Class of an object in this set. */
   1.569 +    inline const Class *getObjectClass(unsigned i) const;
   1.570 +
   1.571 +    bool canSetDefinite(unsigned slot) {
   1.572 +        // Note: the cast is required to work around an MSVC issue.
   1.573 +        return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
   1.574 +    }
   1.575 +    void setDefinite(unsigned slot) {
   1.576 +        JS_ASSERT(canSetDefinite(slot));
   1.577 +        flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
   1.578 +        JS_ASSERT(definiteSlot() == slot);
   1.579 +    }
   1.580 +
   1.581 +    /* Whether any values in this set might have the specified type. */
   1.582 +    bool mightBeMIRType(jit::MIRType type);
   1.583 +
   1.584 +    /*
   1.585 +     * Get whether this type set is known to be a subset of other.
   1.586 +     * This variant doesn't freeze constraints. That variant is called knownSubset
   1.587 +     */
   1.588 +    bool isSubset(TypeSet *other);
   1.589 +
   1.590 +    /* Forward all types in this set to the specified constraint. */
   1.591 +    bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
   1.592 +
   1.593 +    // Clone a type set into an arbitrary allocator.
   1.594 +    TemporaryTypeSet *clone(LifoAlloc *alloc) const;
   1.595 +    bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const;
   1.596 +
   1.597 +    // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
   1.598 +    TemporaryTypeSet *filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const;
   1.599 +
   1.600 +  protected:
   1.601 +    uint32_t baseObjectCount() const {
   1.602 +        return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
   1.603 +    }
   1.604 +    inline void setBaseObjectCount(uint32_t count);
   1.605 +
   1.606 +    void clearObjects();
   1.607 +};
   1.608 +
   1.609 +/* Superclass common to stack and heap type sets. */
   1.610 +class ConstraintTypeSet : public TypeSet
   1.611 +{
   1.612 +  public:
   1.613 +    /* Chain of constraints which propagate changes out from this type set. */
   1.614 +    TypeConstraint *constraintList;
   1.615 +
   1.616 +    ConstraintTypeSet() : constraintList(nullptr) {}
   1.617 +
   1.618 +    /*
   1.619 +     * Add a type to this set, calling any constraint handlers if this is a new
   1.620 +     * possible type.
   1.621 +     */
   1.622 +    void addType(ExclusiveContext *cx, Type type);
   1.623 +
   1.624 +    /* Add a new constraint to this set. */
   1.625 +    bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
   1.626 +
   1.627 +    inline void sweep(JS::Zone *zone, bool *oom);
   1.628 +};
   1.629 +
   1.630 +class StackTypeSet : public ConstraintTypeSet
   1.631 +{
   1.632 +  public:
   1.633 +};
   1.634 +
   1.635 +class HeapTypeSet : public ConstraintTypeSet
   1.636 +{
   1.637 +    inline void newPropertyState(ExclusiveContext *cx);
   1.638 +
   1.639 +  public:
   1.640 +    /* Mark this type set as representing a non-data property. */
   1.641 +    inline void setNonDataProperty(ExclusiveContext *cx);
   1.642 +    inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
   1.643 +
   1.644 +    /* Mark this type set as representing a non-writable property. */
   1.645 +    inline void setNonWritableProperty(ExclusiveContext *cx);
   1.646 +};
   1.647 +
   1.648 +class CompilerConstraintList;
   1.649 +
   1.650 +CompilerConstraintList *
   1.651 +NewCompilerConstraintList(jit::TempAllocator &alloc);
   1.652 +
   1.653 +class TemporaryTypeSet : public TypeSet
   1.654 +{
   1.655 +  public:
   1.656 +    TemporaryTypeSet() {}
   1.657 +    TemporaryTypeSet(Type type);
   1.658 +
   1.659 +    TemporaryTypeSet(uint32_t flags, TypeObjectKey **objectSet) {
   1.660 +        this->flags = flags;
   1.661 +        this->objectSet = objectSet;
   1.662 +    }
   1.663 +
   1.664 +    /*
   1.665 +     * Constraints for JIT compilation.
   1.666 +     *
   1.667 +     * Methods for JIT compilation. These must be used when a script is
   1.668 +     * currently being compiled (see AutoEnterCompilation) and will add
   1.669 +     * constraints ensuring that if the return value change in the future due
   1.670 +     * to new type information, the script's jitcode will be discarded.
   1.671 +     */
   1.672 +
   1.673 +    /* Get any type tag which all values in this set must have. */
   1.674 +    jit::MIRType getKnownMIRType();
   1.675 +
   1.676 +    bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
   1.677 +
   1.678 +    /* Whether this value may be an object. */
   1.679 +    bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
   1.680 +
   1.681 +    /*
   1.682 +     * Whether this typeset represents a potentially sentineled object value:
   1.683 +     * the value may be an object or null or undefined.
   1.684 +     * Returns false if the value cannot ever be an object.
   1.685 +     */
   1.686 +    bool objectOrSentinel() {
   1.687 +        TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
   1.688 +        if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
   1.689 +            return false;
   1.690 +
   1.691 +        return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
   1.692 +    }
   1.693 +
   1.694 +    /* Whether the type set contains objects with any of a set of flags. */
   1.695 +    bool hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
   1.696 +
   1.697 +    /* Get the class shared by all objects in this set, or nullptr. */
   1.698 +    const Class *getKnownClass();
   1.699 +
   1.700 +    /* Result returned from forAllClasses */
   1.701 +    enum ForAllResult {
   1.702 +        EMPTY=1,                // Set empty
   1.703 +        ALL_TRUE,               // Set not empty and predicate returned true for all classes
   1.704 +        ALL_FALSE,              // Set not empty and predicate returned false for all classes
   1.705 +        MIXED,                  // Set not empty and predicate returned false for some classes
   1.706 +                                // and true for others, or set contains an unknown or non-object
   1.707 +                                // type
   1.708 +    };
   1.709 +
   1.710 +    /* Apply func to the members of the set and return an appropriate result.
   1.711 +     * The iteration may end early if the result becomes known early.
   1.712 +     */
   1.713 +    ForAllResult forAllClasses(bool (*func)(const Class *clasp));
   1.714 +
   1.715 +    /* Get the prototype shared by all objects in this set, or nullptr. */
   1.716 +    JSObject *getCommonPrototype();
   1.717 +
   1.718 +    /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */
   1.719 +    int getTypedArrayType();
   1.720 +
   1.721 +    /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
   1.722 +    bool isDOMClass();
   1.723 +
   1.724 +    /* Whether clasp->isCallable() is true for one or more objects in this set. */
   1.725 +    bool maybeCallable();
   1.726 +
   1.727 +    /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
   1.728 +    bool maybeEmulatesUndefined();
   1.729 +
   1.730 +    /* Get the single value which can appear in this type set, otherwise nullptr. */
   1.731 +    JSObject *getSingleton();
   1.732 +
   1.733 +    /* Whether any objects in the type set needs a barrier on id. */
   1.734 +    bool propertyNeedsBarrier(CompilerConstraintList *constraints, jsid id);
   1.735 +
   1.736 +    /*
   1.737 +     * Whether this set contains all types in other, except (possibly) the
   1.738 +     * specified type.
   1.739 +     */
   1.740 +    bool filtersType(const TemporaryTypeSet *other, Type type) const;
   1.741 +
   1.742 +    enum DoubleConversion {
   1.743 +        /* All types in the set should use eager double conversion. */
   1.744 +        AlwaysConvertToDoubles,
   1.745 +
   1.746 +        /* Some types in the set should use eager double conversion. */
   1.747 +        MaybeConvertToDoubles,
   1.748 +
   1.749 +        /* No types should use eager double conversion. */
   1.750 +        DontConvertToDoubles,
   1.751 +
   1.752 +        /* Some types should use eager double conversion, others cannot. */
   1.753 +        AmbiguousDoubleConversion
   1.754 +    };
   1.755 +
   1.756 +    /*
   1.757 +     * Whether known double optimizations are possible for element accesses on
   1.758 +     * objects in this type set.
   1.759 +     */
   1.760 +    DoubleConversion convertDoubleElements(CompilerConstraintList *constraints);
   1.761 +};
   1.762 +
   1.763 +bool
   1.764 +AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id);
   1.765 +
   1.766 +bool
   1.767 +AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
   1.768 +                                     JSScript *script, JSScript *calleeScript);
   1.769 +
   1.770 +/* Is this a reasonable PC to be doing inlining on? */
   1.771 +inline bool isInlinableCall(jsbytecode *pc);
   1.772 +
   1.773 +/* Type information about a property. */
   1.774 +struct Property
   1.775 +{
   1.776 +    /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
   1.777 +    HeapId id;
   1.778 +
   1.779 +    /* Possible types for this property, including types inherited from prototypes. */
   1.780 +    HeapTypeSet types;
   1.781 +
   1.782 +    Property(jsid id)
   1.783 +      : id(id)
   1.784 +    {}
   1.785 +
   1.786 +    Property(const Property &o)
   1.787 +      : id(o.id.get()), types(o.types)
   1.788 +    {}
   1.789 +
   1.790 +    static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
   1.791 +    static jsid getKey(Property *p) { return p->id; }
   1.792 +};
   1.793 +
   1.794 +struct TypeNewScript;
   1.795 +struct TypeTypedObject;
   1.796 +
   1.797 +struct TypeObjectAddendum
   1.798 +{
   1.799 +    enum Kind {
   1.800 +        NewScript,
   1.801 +        TypedObject
   1.802 +    };
   1.803 +
   1.804 +    TypeObjectAddendum(Kind kind);
   1.805 +
   1.806 +    const Kind kind;
   1.807 +
   1.808 +    bool isNewScript() {
   1.809 +        return kind == NewScript;
   1.810 +    }
   1.811 +
   1.812 +    TypeNewScript *asNewScript() {
   1.813 +        JS_ASSERT(isNewScript());
   1.814 +        return (TypeNewScript*) this;
   1.815 +    }
   1.816 +
   1.817 +    bool isTypedObject() {
   1.818 +        return kind == TypedObject;
   1.819 +    }
   1.820 +
   1.821 +    TypeTypedObject *asTypedObject() {
   1.822 +        JS_ASSERT(isTypedObject());
   1.823 +        return (TypeTypedObject*) this;
   1.824 +    }
   1.825 +
   1.826 +    static inline void writeBarrierPre(TypeObjectAddendum *type);
   1.827 +
   1.828 +    static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {}
   1.829 +};
   1.830 +
   1.831 +/*
   1.832 + * Information attached to a TypeObject if it is always constructed using 'new'
   1.833 + * on a particular script. This is used to manage state related to the definite
   1.834 + * properties on the type object: these definite properties depend on type
   1.835 + * information which could change as the script executes (e.g. a scripted
   1.836 + * setter is added to a prototype object), and we need to ensure both that the
   1.837 + * appropriate type constraints are in place when necessary, and that we can
   1.838 + * remove the definite property information and repair the JS stack if the
   1.839 + * constraints are violated.
   1.840 + */
   1.841 +struct TypeNewScript : public TypeObjectAddendum
   1.842 +{
   1.843 +    TypeNewScript();
   1.844 +
   1.845 +    HeapPtrFunction fun;
   1.846 +
   1.847 +    /*
   1.848 +     * Template object to use for newly constructed objects. Reflects all
   1.849 +     * definite properties the object will have and the allocation kind to use
   1.850 +     * for the object. The allocation kind --- and template object itself ---
   1.851 +     * is subject to change if objects allocated with this type are given
   1.852 +     * dynamic slots later on due to new properties being added after the
   1.853 +     * constructor function finishes.
   1.854 +     */
   1.855 +    HeapPtrObject templateObject;
   1.856 +
   1.857 +    /*
   1.858 +     * Order in which properties become initialized. We need this in case a
   1.859 +     * scripted setter is added to one of the object's prototypes while it is
   1.860 +     * in the middle of being initialized, so we can walk the stack and fixup
   1.861 +     * any objects which look for in-progress objects which were prematurely
   1.862 +     * set with their final shape. Property assignments in inner frames are
   1.863 +     * preceded by a series of SETPROP_FRAME entries specifying the stack down
   1.864 +     * to the frame containing the write.
   1.865 +     */
   1.866 +    struct Initializer {
   1.867 +        enum Kind {
   1.868 +            SETPROP,
   1.869 +            SETPROP_FRAME,
   1.870 +            DONE
   1.871 +        } kind;
   1.872 +        uint32_t offset;
   1.873 +        Initializer(Kind kind, uint32_t offset)
   1.874 +          : kind(kind), offset(offset)
   1.875 +        {}
   1.876 +    };
   1.877 +    Initializer *initializerList;
   1.878 +
   1.879 +    static inline void writeBarrierPre(TypeNewScript *newScript);
   1.880 +};
   1.881 +
   1.882 +struct TypeTypedObject : public TypeObjectAddendum
   1.883 +{
   1.884 +  private:
   1.885 +    HeapPtrObject descr_;
   1.886 +
   1.887 +  public:
   1.888 +    TypeTypedObject(Handle<TypeDescr*> descr);
   1.889 +
   1.890 +    HeapPtrObject &descrHeapPtr() {
   1.891 +        return descr_;
   1.892 +    }
   1.893 +
   1.894 +    TypeDescr &descr();
   1.895 +};
   1.896 +
   1.897 +/*
   1.898 + * Lazy type objects overview.
   1.899 + *
   1.900 + * Type objects which represent at most one JS object are constructed lazily.
   1.901 + * These include types for native functions, standard classes, scripted
   1.902 + * functions defined at the top level of global/eval scripts, and in some
   1.903 + * other cases. Typical web workloads often create many windows (and many
   1.904 + * copies of standard natives) and many scripts, with comparatively few
   1.905 + * non-singleton types.
   1.906 + *
   1.907 + * We can recover the type information for the object from examining it,
   1.908 + * so don't normally track the possible types of its properties as it is
   1.909 + * updated. Property type sets for the object are only constructed when an
   1.910 + * analyzed script attaches constraints to it: the script is querying that
   1.911 + * property off the object or another which delegates to it, and the analysis
   1.912 + * information is sensitive to changes in the property's type. Future changes
   1.913 + * to the property (whether those uncovered by analysis or those occurring
   1.914 + * in the VM) will treat these properties like those of any other type object.
   1.915 + */
   1.916 +
   1.917 +/* Type information about an object accessed by a script. */
   1.918 +struct TypeObject : gc::BarrieredCell<TypeObject>
   1.919 +{
   1.920 +  private:
   1.921 +    /* Class shared by object using this type. */
   1.922 +    const Class *clasp_;
   1.923 +
   1.924 +    /* Prototype shared by objects using this type. */
   1.925 +    HeapPtrObject proto_;
   1.926 +
   1.927 +    /*
   1.928 +     * Whether there is a singleton JS object with this type. That JS object
   1.929 +     * must appear in type sets instead of this; we include the back reference
   1.930 +     * here to allow reverting the JS object to a lazy type.
   1.931 +     */
   1.932 +    HeapPtrObject singleton_;
   1.933 +
   1.934 +  public:
   1.935 +
   1.936 +    const Class *clasp() const {
   1.937 +        return clasp_;
   1.938 +    }
   1.939 +
   1.940 +    void setClasp(const Class *clasp) {
   1.941 +        JS_ASSERT(singleton());
   1.942 +        clasp_ = clasp;
   1.943 +    }
   1.944 +
   1.945 +    TaggedProto proto() const {
   1.946 +        return TaggedProto(proto_);
   1.947 +    }
   1.948 +
   1.949 +    JSObject *singleton() const {
   1.950 +        return singleton_;
   1.951 +    }
   1.952 +
   1.953 +    // For use during marking, don't call otherwise.
   1.954 +    HeapPtrObject &protoRaw() { return proto_; }
   1.955 +    HeapPtrObject &singletonRaw() { return singleton_; }
   1.956 +
   1.957 +    void setProto(JSContext *cx, TaggedProto proto);
   1.958 +    void setProtoUnchecked(TaggedProto proto) {
   1.959 +        proto_ = proto.raw();
   1.960 +    }
   1.961 +
   1.962 +    void initSingleton(JSObject *singleton) {
   1.963 +        singleton_ = singleton;
   1.964 +    }
   1.965 +
   1.966 +    /*
   1.967 +     * Value held by singleton if this is a standin type for a singleton JS
   1.968 +     * object whose type has not been constructed yet.
   1.969 +     */
   1.970 +    static const size_t LAZY_SINGLETON = 1;
   1.971 +    bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; }
   1.972 +
   1.973 +  private:
   1.974 +    /* Flags for this object. */
   1.975 +    TypeObjectFlags flags_;
   1.976 +
   1.977 +    /*
   1.978 +     * This field allows various special classes of objects to attach
   1.979 +     * additional information to a type object:
   1.980 +     *
   1.981 +     * - `TypeNewScript`: If addendum is a `TypeNewScript`, it
   1.982 +     *   indicates that objects of this type have always been
   1.983 +     *   constructed using 'new' on the specified script, which adds
   1.984 +     *   some number of properties to the object in a definite order
   1.985 +     *   before the object escapes.
   1.986 +     */
   1.987 +    HeapPtr<TypeObjectAddendum> addendum;
   1.988 +  public:
   1.989 +
   1.990 +    TypeObjectFlags flags() const {
   1.991 +        return flags_;
   1.992 +    }
   1.993 +
   1.994 +    void addFlags(TypeObjectFlags flags) {
   1.995 +        flags_ |= flags;
   1.996 +    }
   1.997 +
   1.998 +    void clearFlags(TypeObjectFlags flags) {
   1.999 +        flags_ &= ~flags;
  1.1000 +    }
  1.1001 +
  1.1002 +    bool hasNewScript() const {
  1.1003 +        return addendum && addendum->isNewScript();
  1.1004 +    }
  1.1005 +
  1.1006 +    TypeNewScript *newScript() {
  1.1007 +        return addendum->asNewScript();
  1.1008 +    }
  1.1009 +
  1.1010 +    bool hasTypedObject() {
  1.1011 +        return addendum && addendum->isTypedObject();
  1.1012 +    }
  1.1013 +
  1.1014 +    TypeTypedObject *typedObject() {
  1.1015 +        return addendum->asTypedObject();
  1.1016 +    }
  1.1017 +
  1.1018 +    void setAddendum(TypeObjectAddendum *addendum);
  1.1019 +
  1.1020 +    /*
  1.1021 +     * Tag the type object for a binary data type descriptor, instance,
  1.1022 +     * or handle with the type representation of the data it points at.
  1.1023 +     * If this type object is already tagged with a binary data addendum,
  1.1024 +     * this addendum must already be associated with the same TypeRepresentation,
  1.1025 +     * and the method has no effect.
  1.1026 +     */
  1.1027 +    bool addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr);
  1.1028 +
  1.1029 +  private:
  1.1030 +    /*
  1.1031 +     * Properties of this object. This may contain JSID_VOID, representing the
  1.1032 +     * types of all integer indexes of the object, and/or JSID_EMPTY, holding
  1.1033 +     * constraints listening to changes to the object's state.
  1.1034 +     *
  1.1035 +     * The type sets in the properties of a type object describe the possible
  1.1036 +     * values that can be read out of that property in actual JS objects.
  1.1037 +     * Properties only account for native properties (those with a slot and no
  1.1038 +     * specialized getter hook) and the elements of dense arrays. For accesses
  1.1039 +     * on such properties, the correspondence is as follows:
  1.1040 +     *
  1.1041 +     * 1. If the type has unknownProperties(), the possible properties and
  1.1042 +     *    value types for associated JSObjects are unknown.
  1.1043 +     *
  1.1044 +     * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
  1.1045 +     *    which is a property in obj, before obj->getProperty(id) the property
  1.1046 +     *    in type for id must reflect the result of the getProperty.
  1.1047 +     *
  1.1048 +     *    There is an exception for properties of global JS objects which
  1.1049 +     *    are undefined at the point where the property was (lazily) generated.
  1.1050 +     *    In such cases the property type set will remain empty, and the
  1.1051 +     *    'undefined' type will only be added after a subsequent assignment or
  1.1052 +     *    deletion. After these properties have been assigned a defined value,
  1.1053 +     *    the only way they can become undefined again is after such an assign
  1.1054 +     *    or deletion.
  1.1055 +     *
  1.1056 +     *    There is another exception for array lengths, which are special cased
  1.1057 +     *    by the compiler and VM and are not reflected in property types.
  1.1058 +     *
  1.1059 +     * We establish these by using write barriers on calls to setProperty and
  1.1060 +     * defineProperty which are on native properties, and on any jitcode which
  1.1061 +     * might update the property with a new type.
  1.1062 +     */
  1.1063 +    Property **propertySet;
  1.1064 +  public:
  1.1065 +
  1.1066 +    /* If this is an interpreted function, the function object. */
  1.1067 +    HeapPtrFunction interpretedFunction;
  1.1068 +
  1.1069 +#if JS_BITS_PER_WORD == 32
  1.1070 +    uint32_t padding;
  1.1071 +#endif
  1.1072 +
  1.1073 +    inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags);
  1.1074 +
  1.1075 +    bool hasAnyFlags(TypeObjectFlags flags) {
  1.1076 +        JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
  1.1077 +        return !!(this->flags() & flags);
  1.1078 +    }
  1.1079 +    bool hasAllFlags(TypeObjectFlags flags) {
  1.1080 +        JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
  1.1081 +        return (this->flags() & flags) == flags;
  1.1082 +    }
  1.1083 +
  1.1084 +    bool unknownProperties() {
  1.1085 +        JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
  1.1086 +                     hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
  1.1087 +        return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
  1.1088 +    }
  1.1089 +
  1.1090 +    bool shouldPreTenure() {
  1.1091 +        return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
  1.1092 +    }
  1.1093 +
  1.1094 +    bool hasTenuredProto() const {
  1.1095 +        return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
  1.1096 +    }
  1.1097 +
  1.1098 +    gc::InitialHeap initialHeap(CompilerConstraintList *constraints);
  1.1099 +
  1.1100 +    bool canPreTenure() {
  1.1101 +        // Only types associated with particular allocation sites or 'new'
  1.1102 +        // scripts can be marked as needing pretenuring. Other types can be
  1.1103 +        // used for different purposes across the compartment and can't use
  1.1104 +        // this bit reliably.
  1.1105 +        if (unknownProperties())
  1.1106 +            return false;
  1.1107 +        return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
  1.1108 +    }
  1.1109 +
  1.1110 +    void setShouldPreTenure(ExclusiveContext *cx) {
  1.1111 +        JS_ASSERT(canPreTenure());
  1.1112 +        setFlags(cx, OBJECT_FLAG_PRE_TENURE);
  1.1113 +    }
  1.1114 +
  1.1115 +    /*
  1.1116 +     * Get or create a property of this object. Only call this for properties which
  1.1117 +     * a script accesses explicitly.
  1.1118 +     */
  1.1119 +    inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id);
  1.1120 +
  1.1121 +    /* Get a property only if it already exists. */
  1.1122 +    inline HeapTypeSet *maybeGetProperty(jsid id);
  1.1123 +
  1.1124 +    inline unsigned getPropertyCount();
  1.1125 +    inline Property *getProperty(unsigned i);
  1.1126 +
  1.1127 +    /* Helpers */
  1.1128 +
  1.1129 +    void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, HeapTypeSet *types);
  1.1130 +    bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj);
  1.1131 +    bool matchDefiniteProperties(HandleObject obj);
  1.1132 +    void addPrototype(JSContext *cx, TypeObject *proto);
  1.1133 +    void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
  1.1134 +    void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
  1.1135 +    void markPropertyNonData(ExclusiveContext *cx, jsid id);
  1.1136 +    void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
  1.1137 +    void markStateChange(ExclusiveContext *cx);
  1.1138 +    void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
  1.1139 +    void markUnknown(ExclusiveContext *cx);
  1.1140 +    void clearAddendum(ExclusiveContext *cx);
  1.1141 +    void clearNewScriptAddendum(ExclusiveContext *cx);
  1.1142 +    void clearTypedObjectAddendum(ExclusiveContext *cx);
  1.1143 +    void maybeClearNewScriptAddendumOnOOM();
  1.1144 +    bool isPropertyNonData(jsid id);
  1.1145 +    bool isPropertyNonWritable(jsid id);
  1.1146 +
  1.1147 +    void print();
  1.1148 +
  1.1149 +    inline void clearProperties();
  1.1150 +    inline void sweep(FreeOp *fop, bool *oom);
  1.1151 +
  1.1152 +    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
  1.1153 +
  1.1154 +    /*
  1.1155 +     * Type objects don't have explicit finalizers. Memory owned by a type
  1.1156 +     * object pending deletion is released when weak references are sweeped
  1.1157 +     * from all the compartment's type objects.
  1.1158 +     */
  1.1159 +    void finalize(FreeOp *fop) {}
  1.1160 +
  1.1161 +    static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
  1.1162 +
  1.1163 +    static inline uint32_t offsetOfClasp() {
  1.1164 +        return offsetof(TypeObject, clasp_);
  1.1165 +    }
  1.1166 +
  1.1167 +    static inline uint32_t offsetOfProto() {
  1.1168 +        return offsetof(TypeObject, proto_);
  1.1169 +    }
  1.1170 +
  1.1171 +  private:
  1.1172 +    inline uint32_t basePropertyCount() const;
  1.1173 +    inline void setBasePropertyCount(uint32_t count);
  1.1174 +
  1.1175 +    static void staticAsserts() {
  1.1176 +        JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
  1.1177 +    }
  1.1178 +};
  1.1179 +
  1.1180 +/*
  1.1181 + * Entries for the per-compartment set of type objects which are 'new' types to
  1.1182 + * use for some prototype and constructed with an optional script. This also
  1.1183 + * includes entries for the set of lazy type objects in the compartment, which
  1.1184 + * use a null script (though there are only a few of these per compartment).
  1.1185 + */
  1.1186 +struct TypeObjectWithNewScriptEntry
  1.1187 +{
  1.1188 +    ReadBarriered<TypeObject> object;
  1.1189 +
  1.1190 +    // Note: This pointer is only used for equality and does not need a read barrier.
  1.1191 +    JSFunction *newFunction;
  1.1192 +
  1.1193 +    TypeObjectWithNewScriptEntry(TypeObject *object, JSFunction *newFunction)
  1.1194 +      : object(object), newFunction(newFunction)
  1.1195 +    {}
  1.1196 +
  1.1197 +    struct Lookup {
  1.1198 +        const Class *clasp;
  1.1199 +        TaggedProto hashProto;
  1.1200 +        TaggedProto matchProto;
  1.1201 +        JSFunction *newFunction;
  1.1202 +
  1.1203 +        Lookup(const Class *clasp, TaggedProto proto, JSFunction *newFunction)
  1.1204 +          : clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction)
  1.1205 +        {}
  1.1206 +
  1.1207 +#ifdef JSGC_GENERATIONAL
  1.1208 +        /*
  1.1209 +         * For use by generational post barriers only.  Look up an entry whose
  1.1210 +         * proto has been moved, but was hashed with the original value.
  1.1211 +         */
  1.1212 +        Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction *newFunction)
  1.1213 +            : clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction)
  1.1214 +        {}
  1.1215 +#endif
  1.1216 +
  1.1217 +    };
  1.1218 +
  1.1219 +    static inline HashNumber hash(const Lookup &lookup);
  1.1220 +    static inline bool match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup);
  1.1221 +    static void rekey(TypeObjectWithNewScriptEntry &k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; }
  1.1222 +};
  1.1223 +typedef HashSet<TypeObjectWithNewScriptEntry,
  1.1224 +                TypeObjectWithNewScriptEntry,
  1.1225 +                SystemAllocPolicy> TypeObjectWithNewScriptSet;
  1.1226 +
  1.1227 +/* Whether to use a new type object when calling 'new' at script/pc. */
  1.1228 +bool
  1.1229 +UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
  1.1230 +
  1.1231 +bool
  1.1232 +UseNewTypeForClone(JSFunction *fun);
  1.1233 +
  1.1234 +/*
  1.1235 + * Whether Array.prototype, or an object on its proto chain, has an
  1.1236 + * indexed property.
  1.1237 + */
  1.1238 +bool
  1.1239 +ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSScript *script);
  1.1240 +
  1.1241 +/* Whether obj or any of its prototypes have an indexed property. */
  1.1242 +bool
  1.1243 +TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, TemporaryTypeSet *types);
  1.1244 +
  1.1245 +/* Persistent type information for a script, retained across GCs. */
  1.1246 +class TypeScript
  1.1247 +{
  1.1248 +    friend class ::JSScript;
  1.1249 +
  1.1250 +    // Variable-size array
  1.1251 +    StackTypeSet typeArray_[1];
  1.1252 +
  1.1253 +  public:
  1.1254 +    /* Array of type type sets for variables and JOF_TYPESET ops. */
  1.1255 +    StackTypeSet *typeArray() const {
  1.1256 +        // Ensure typeArray_ is the last data member of TypeScript.
  1.1257 +        JS_STATIC_ASSERT(sizeof(TypeScript) ==
  1.1258 +            sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
  1.1259 +        return const_cast<StackTypeSet *>(typeArray_);
  1.1260 +    }
  1.1261 +
  1.1262 +    static inline size_t SizeIncludingTypeArray(size_t arraySize) {
  1.1263 +        // Ensure typeArray_ is the last data member of TypeScript.
  1.1264 +        JS_STATIC_ASSERT(sizeof(TypeScript) ==
  1.1265 +            sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
  1.1266 +        return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
  1.1267 +    }
  1.1268 +
  1.1269 +    static inline unsigned NumTypeSets(JSScript *script);
  1.1270 +
  1.1271 +    static inline StackTypeSet *ThisTypes(JSScript *script);
  1.1272 +    static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i);
  1.1273 +
  1.1274 +    /* Get the type set for values observed at an opcode. */
  1.1275 +    static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc);
  1.1276 +
  1.1277 +    template <typename TYPESET>
  1.1278 +    static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap,
  1.1279 +                                         uint32_t *hint, TYPESET *typeArray);
  1.1280 +
  1.1281 +    /* Get a type object for an allocation site in this script. */
  1.1282 +    static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc,
  1.1283 +                                         JSProtoKey kind);
  1.1284 +
  1.1285 +    /*
  1.1286 +     * Monitor a bytecode pushing any value. This must be called for any opcode
  1.1287 +     * which is JOF_TYPESET, and where either the script has not been analyzed
  1.1288 +     * by type inference or where the pc has type barriers. For simplicity, we
  1.1289 +     * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
  1.1290 +     * and only look at barriers when generating JIT code for the script.
  1.1291 +     */
  1.1292 +    static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
  1.1293 +                               const js::Value &val);
  1.1294 +    static inline void Monitor(JSContext *cx, const js::Value &rval);
  1.1295 +
  1.1296 +    /* Monitor an assignment at a SETELEM on a non-integer identifier. */
  1.1297 +    static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id);
  1.1298 +
  1.1299 +    /* Add a type for a variable in a script. */
  1.1300 +    static inline void SetThis(JSContext *cx, JSScript *script, Type type);
  1.1301 +    static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
  1.1302 +    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
  1.1303 +    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg,
  1.1304 +                                   const js::Value &value);
  1.1305 +
  1.1306 +    /*
  1.1307 +     * Freeze all the stack type sets in a script, for a compilation. Returns
  1.1308 +     * copies of the type sets which will be checked against the actual ones
  1.1309 +     * under FinishCompilation, to detect any type changes.
  1.1310 +     */
  1.1311 +    static bool FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script,
  1.1312 +                               TemporaryTypeSet **pThisTypes,
  1.1313 +                               TemporaryTypeSet **pArgTypes,
  1.1314 +                               TemporaryTypeSet **pBytecodeTypes);
  1.1315 +
  1.1316 +    static void Purge(JSContext *cx, HandleScript script);
  1.1317 +
  1.1318 +    static void Sweep(FreeOp *fop, JSScript *script, bool *oom);
  1.1319 +    void destroy();
  1.1320 +
  1.1321 +    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  1.1322 +        return mallocSizeOf(this);
  1.1323 +    }
  1.1324 +
  1.1325 +#ifdef DEBUG
  1.1326 +    void printTypes(JSContext *cx, HandleScript script) const;
  1.1327 +#endif
  1.1328 +};
  1.1329 +
  1.1330 +void
  1.1331 +FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap);
  1.1332 +
  1.1333 +class RecompileInfo;
  1.1334 +
  1.1335 +// Allocate a CompilerOutput for a finished compilation and generate the type
  1.1336 +// constraints for the compilation. Returns whether the type constraints
  1.1337 +// still hold.
  1.1338 +bool
  1.1339 +FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode executionMode,
  1.1340 +                  CompilerConstraintList *constraints, RecompileInfo *precompileInfo);
  1.1341 +
  1.1342 +// Update the actual types in any scripts queried by constraints with any
  1.1343 +// speculative types added during the definite properties analysis.
  1.1344 +void
  1.1345 +FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *constraints);
  1.1346 +
  1.1347 +struct ArrayTableKey;
  1.1348 +typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
  1.1349 +
  1.1350 +struct ObjectTableKey;
  1.1351 +struct ObjectTableEntry;
  1.1352 +typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
  1.1353 +
  1.1354 +struct AllocationSiteKey;
  1.1355 +typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
  1.1356 +
  1.1357 +class HeapTypeSetKey;
  1.1358 +
  1.1359 +// Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
  1.1360 +struct TypeObjectKey
  1.1361 +{
  1.1362 +    static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
  1.1363 +    static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
  1.1364 +
  1.1365 +    static TypeObjectKey *get(JSObject *obj) {
  1.1366 +        JS_ASSERT(obj);
  1.1367 +        return (TypeObjectKey *) (uintptr_t(obj) | 1);
  1.1368 +    }
  1.1369 +    static TypeObjectKey *get(TypeObject *obj) {
  1.1370 +        JS_ASSERT(obj);
  1.1371 +        return (TypeObjectKey *) obj;
  1.1372 +    }
  1.1373 +
  1.1374 +    bool isTypeObject() {
  1.1375 +        return (uintptr_t(this) & 1) == 0;
  1.1376 +    }
  1.1377 +    bool isSingleObject() {
  1.1378 +        return (uintptr_t(this) & 1) != 0;
  1.1379 +    }
  1.1380 +
  1.1381 +    TypeObject *asTypeObject() {
  1.1382 +        JS_ASSERT(isTypeObject());
  1.1383 +        return (TypeObject *) this;
  1.1384 +    }
  1.1385 +    JSObject *asSingleObject() {
  1.1386 +        JS_ASSERT(isSingleObject());
  1.1387 +        return (JSObject *) (uintptr_t(this) & ~1);
  1.1388 +    }
  1.1389 +
  1.1390 +    const Class *clasp();
  1.1391 +    TaggedProto proto();
  1.1392 +    bool hasTenuredProto();
  1.1393 +    JSObject *singleton();
  1.1394 +    TypeNewScript *newScript();
  1.1395 +
  1.1396 +    bool unknownProperties();
  1.1397 +    bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
  1.1398 +    void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
  1.1399 +    void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints);
  1.1400 +    void watchStateChangeForTypedArrayData(CompilerConstraintList *constraints);
  1.1401 +    HeapTypeSetKey property(jsid id);
  1.1402 +    void ensureTrackedProperty(JSContext *cx, jsid id);
  1.1403 +
  1.1404 +    TypeObject *maybeType();
  1.1405 +};
  1.1406 +
  1.1407 +// Representation of a heap type property which may or may not be instantiated.
  1.1408 +// Heap properties for singleton types are instantiated lazily as they are used
  1.1409 +// by the compiler, but this is only done on the main thread. If we are
  1.1410 +// compiling off thread and use a property which has not yet been instantiated,
  1.1411 +// it will be treated as empty and non-configured and will be instantiated when
  1.1412 +// rejoining to the main thread. If it is in fact not empty, the compilation
  1.1413 +// will fail; to avoid this, we try to instantiate singleton property types
  1.1414 +// during generation of baseline caches.
  1.1415 +class HeapTypeSetKey
  1.1416 +{
  1.1417 +    friend class TypeObjectKey;
  1.1418 +
  1.1419 +    // Object and property being accessed.
  1.1420 +    TypeObjectKey *object_;
  1.1421 +    jsid id_;
  1.1422 +
  1.1423 +    // If instantiated, the underlying heap type set.
  1.1424 +    HeapTypeSet *maybeTypes_;
  1.1425 +
  1.1426 +  public:
  1.1427 +    HeapTypeSetKey()
  1.1428 +      : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
  1.1429 +    {}
  1.1430 +
  1.1431 +    TypeObjectKey *object() const { return object_; }
  1.1432 +    jsid id() const { return id_; }
  1.1433 +    HeapTypeSet *maybeTypes() const { return maybeTypes_; }
  1.1434 +
  1.1435 +    bool instantiate(JSContext *cx);
  1.1436 +
  1.1437 +    void freeze(CompilerConstraintList *constraints);
  1.1438 +    jit::MIRType knownMIRType(CompilerConstraintList *constraints);
  1.1439 +    bool nonData(CompilerConstraintList *constraints);
  1.1440 +    bool nonWritable(CompilerConstraintList *constraints);
  1.1441 +    bool isOwnProperty(CompilerConstraintList *constraints);
  1.1442 +    bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
  1.1443 +    JSObject *singleton(CompilerConstraintList *constraints);
  1.1444 +    bool needsBarrier(CompilerConstraintList *constraints);
  1.1445 +};
  1.1446 +
  1.1447 +/*
  1.1448 + * Information about the result of the compilation of a script.  This structure
  1.1449 + * stored in the TypeCompartment is indexed by the RecompileInfo. This
  1.1450 + * indirection enables the invalidation of all constraints related to the same
  1.1451 + * compilation.
  1.1452 + */
  1.1453 +class CompilerOutput
  1.1454 +{
  1.1455 +    // If this compilation has not been invalidated, the associated script and
  1.1456 +    // kind of compilation being performed.
  1.1457 +    JSScript *script_;
  1.1458 +    ExecutionMode mode_ : 2;
  1.1459 +
  1.1460 +    // Whether this compilation is about to be invalidated.
  1.1461 +    bool pendingInvalidation_ : 1;
  1.1462 +
  1.1463 +    // During sweeping, the list of compiler outputs is compacted and invalidated
  1.1464 +    // outputs are removed. This gives the new index for a valid compiler output.
  1.1465 +    uint32_t sweepIndex_ : 29;
  1.1466 +
  1.1467 +  public:
  1.1468 +    static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1;
  1.1469 +
  1.1470 +    CompilerOutput()
  1.1471 +      : script_(nullptr), mode_(SequentialExecution),
  1.1472 +        pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
  1.1473 +    {}
  1.1474 +
  1.1475 +    CompilerOutput(JSScript *script, ExecutionMode mode)
  1.1476 +      : script_(script), mode_(mode),
  1.1477 +        pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
  1.1478 +    {}
  1.1479 +
  1.1480 +    JSScript *script() const { return script_; }
  1.1481 +    inline ExecutionMode mode() const { return mode_; }
  1.1482 +
  1.1483 +    inline jit::IonScript *ion() const;
  1.1484 +
  1.1485 +    bool isValid() const {
  1.1486 +        return script_ != nullptr;
  1.1487 +    }
  1.1488 +    void invalidate() {
  1.1489 +        script_ = nullptr;
  1.1490 +    }
  1.1491 +
  1.1492 +    void setPendingInvalidation() {
  1.1493 +        pendingInvalidation_ = true;
  1.1494 +    }
  1.1495 +    bool pendingInvalidation() {
  1.1496 +        return pendingInvalidation_;
  1.1497 +    }
  1.1498 +
  1.1499 +    void setSweepIndex(uint32_t index) {
  1.1500 +        if (index >= INVALID_SWEEP_INDEX)
  1.1501 +            MOZ_CRASH();
  1.1502 +        sweepIndex_ = index;
  1.1503 +    }
  1.1504 +    void invalidateSweepIndex() {
  1.1505 +        sweepIndex_ = INVALID_SWEEP_INDEX;
  1.1506 +    }
  1.1507 +    uint32_t sweepIndex() {
  1.1508 +        JS_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
  1.1509 +        return sweepIndex_;
  1.1510 +    }
  1.1511 +};
  1.1512 +
  1.1513 +class RecompileInfo
  1.1514 +{
  1.1515 +    uint32_t outputIndex;
  1.1516 +
  1.1517 +  public:
  1.1518 +    RecompileInfo(uint32_t outputIndex = uint32_t(-1))
  1.1519 +      : outputIndex(outputIndex)
  1.1520 +    {}
  1.1521 +
  1.1522 +    bool operator == (const RecompileInfo &o) const {
  1.1523 +        return outputIndex == o.outputIndex;
  1.1524 +    }
  1.1525 +    CompilerOutput *compilerOutput(TypeZone &types) const;
  1.1526 +    CompilerOutput *compilerOutput(JSContext *cx) const;
  1.1527 +    bool shouldSweep(TypeZone &types);
  1.1528 +};
  1.1529 +
  1.1530 +/* Type information for a compartment. */
  1.1531 +struct TypeCompartment
  1.1532 +{
  1.1533 +    /* Constraint solving worklist structures. */
  1.1534 +
  1.1535 +    /* Number of scripts in this compartment. */
  1.1536 +    unsigned scriptCount;
  1.1537 +
  1.1538 +    /* Table for referencing types of objects keyed to an allocation site. */
  1.1539 +    AllocationSiteTable *allocationSiteTable;
  1.1540 +
  1.1541 +    /* Tables for determining types of singleton/JSON objects. */
  1.1542 +
  1.1543 +    ArrayTypeTable *arrayTypeTable;
  1.1544 +    ObjectTypeTable *objectTypeTable;
  1.1545 +
  1.1546 +  private:
  1.1547 +    void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type);
  1.1548 +
  1.1549 +  public:
  1.1550 +    void fixArrayType(ExclusiveContext *cx, JSObject *obj);
  1.1551 +    void fixObjectType(ExclusiveContext *cx, JSObject *obj);
  1.1552 +    void fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj);
  1.1553 +
  1.1554 +    JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties);
  1.1555 +
  1.1556 +    TypeCompartment();
  1.1557 +    ~TypeCompartment();
  1.1558 +
  1.1559 +    inline JSCompartment *compartment();
  1.1560 +
  1.1561 +    /* Prints results of this compartment if spew is enabled or force is set. */
  1.1562 +    void print(JSContext *cx, bool force);
  1.1563 +
  1.1564 +    /*
  1.1565 +     * Make a function or non-function object associated with an optional
  1.1566 +     * script. The 'key' parameter here may be an array, typed array, function
  1.1567 +     * or JSProto_Object to indicate a type whose class is unknown (not just
  1.1568 +     * js_ObjectClass).
  1.1569 +     */
  1.1570 +    TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
  1.1571 +                              TypeObjectFlags initialFlags = 0);
  1.1572 +
  1.1573 +    /* Get or make an object for an allocation site, and add to the allocation site table. */
  1.1574 +    TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
  1.1575 +
  1.1576 +    /* Mark any type set containing obj as having a generic object type. */
  1.1577 +    void markSetsUnknown(JSContext *cx, TypeObject *obj);
  1.1578 +
  1.1579 +    void clearTables();
  1.1580 +    void sweep(FreeOp *fop);
  1.1581 +    void finalizeObjects();
  1.1582 +
  1.1583 +    void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
  1.1584 +                                size_t *allocationSiteTables,
  1.1585 +                                size_t *arrayTypeTables,
  1.1586 +                                size_t *objectTypeTables);
  1.1587 +};
  1.1588 +
  1.1589 +void FixRestArgumentsType(ExclusiveContext *cxArg, JSObject *obj);
  1.1590 +
  1.1591 +struct TypeZone
  1.1592 +{
  1.1593 +    JS::Zone                     *zone_;
  1.1594 +
  1.1595 +    /* Pool for type information in this zone. */
  1.1596 +    static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
  1.1597 +    js::LifoAlloc                typeLifoAlloc;
  1.1598 +
  1.1599 +    /*
  1.1600 +     * All Ion compilations that have occured in this zone, for indexing via
  1.1601 +     * RecompileInfo. This includes both valid and invalid compilations, though
  1.1602 +     * invalidated compilations are swept on GC.
  1.1603 +     */
  1.1604 +    Vector<CompilerOutput> *compilerOutputs;
  1.1605 +
  1.1606 +    /* Pending recompilations to perform before execution of JIT code can resume. */
  1.1607 +    Vector<RecompileInfo> *pendingRecompiles;
  1.1608 +
  1.1609 +    TypeZone(JS::Zone *zone);
  1.1610 +    ~TypeZone();
  1.1611 +
  1.1612 +    JS::Zone *zone() const { return zone_; }
  1.1613 +
  1.1614 +    void sweep(FreeOp *fop, bool releaseTypes, bool *oom);
  1.1615 +    void clearAllNewScriptAddendumsOnOOM();
  1.1616 +
  1.1617 +    /* Mark a script as needing recompilation once inference has finished. */
  1.1618 +    void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
  1.1619 +    void addPendingRecompile(JSContext *cx, JSScript *script);
  1.1620 +
  1.1621 +    void processPendingRecompiles(FreeOp *fop);
  1.1622 +};
  1.1623 +
  1.1624 +enum SpewChannel {
  1.1625 +    ISpewOps,      /* ops: New constraints and types. */
  1.1626 +    ISpewResult,   /* result: Final type sets. */
  1.1627 +    SPEW_COUNT
  1.1628 +};
  1.1629 +
  1.1630 +#ifdef DEBUG
  1.1631 +
  1.1632 +const char * InferSpewColorReset();
  1.1633 +const char * InferSpewColor(TypeConstraint *constraint);
  1.1634 +const char * InferSpewColor(TypeSet *types);
  1.1635 +
  1.1636 +void InferSpew(SpewChannel which, const char *fmt, ...);
  1.1637 +const char * TypeString(Type type);
  1.1638 +const char * TypeObjectString(TypeObject *type);
  1.1639 +
  1.1640 +/* Check that the type property for id in obj contains value. */
  1.1641 +bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
  1.1642 +
  1.1643 +#else
  1.1644 +
  1.1645 +inline const char * InferSpewColorReset() { return nullptr; }
  1.1646 +inline const char * InferSpewColor(TypeConstraint *constraint) { return nullptr; }
  1.1647 +inline const char * InferSpewColor(TypeSet *types) { return nullptr; }
  1.1648 +inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
  1.1649 +inline const char * TypeString(Type type) { return nullptr; }
  1.1650 +inline const char * TypeObjectString(TypeObject *type) { return nullptr; }
  1.1651 +
  1.1652 +#endif
  1.1653 +
  1.1654 +/* Print a warning, dump state and abort the program. */
  1.1655 +MOZ_NORETURN void TypeFailure(JSContext *cx, const char *fmt, ...);
  1.1656 +
  1.1657 +} /* namespace types */
  1.1658 +} /* namespace js */
  1.1659 +
  1.1660 +#endif /* jsinfer_h */

mercurial