LCOV - code coverage report
Current view: directory - js/src - jsinfer.h (source / functions) Found Hit Coverage
Test: app.info Lines: 110 109 99.1 %
Date: 2012-06-02 Functions: 63 62 98.4 %

       1                 : //* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
       2                 : /* vim: set ts=40 sw=4 et tw=99: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is the Mozilla SpiderMonkey bytecode type inference
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  *   Mozilla Foundation
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Brian Hackett <bhackett@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /* Definitions related to javascript type inference. */
      41                 : 
      42                 : #ifndef jsinfer_h___
      43                 : #define jsinfer_h___
      44                 : 
      45                 : #include "jsalloc.h"
      46                 : #include "jscell.h"
      47                 : #include "jsfriendapi.h"
      48                 : #include "jsprvtd.h"
      49                 : 
      50                 : #include "ds/LifoAlloc.h"
      51                 : #include "gc/Barrier.h"
      52                 : #include "js/HashTable.h"
      53                 : 
      54                 : namespace JS {
      55                 : struct TypeInferenceSizes;
      56                 : }
      57                 : 
      58                 : namespace js {
      59                 : namespace types {
      60                 : 
      61                 : /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
      62                 : struct TypeObjectKey {
      63         2205374 :     static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
      64        47316052 :     static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
      65                 : };
      66                 : 
      67                 : /*
      68                 :  * Information about a single concrete type. We pack this into a single word,
      69                 :  * where small values are particular primitive or other singleton types, and
      70                 :  * larger values are either specific JS objects or type objects.
      71                 :  */
      72                 : class Type
      73                 : {
      74                 :     uintptr_t data;
      75       178307506 :     Type(uintptr_t data) : data(data) {}
      76                 : 
      77                 :   public:
      78                 : 
      79            1555 :     uintptr_t raw() const { return data; }
      80                 : 
      81       302230424 :     bool isPrimitive() const {
      82       302230424 :         return data < JSVAL_TYPE_OBJECT;
      83                 :     }
      84                 : 
      85          166294 :     bool isPrimitive(JSValueType type) const {
      86          166294 :         JS_ASSERT(type < JSVAL_TYPE_OBJECT);
      87          166294 :         return (uintptr_t) type == data;
      88                 :     }
      89                 : 
      90       125132500 :     JSValueType primitive() const {
      91       125132500 :         JS_ASSERT(isPrimitive());
      92       125132500 :         return (JSValueType) data;
      93                 :     }
      94                 : 
      95       114119106 :     bool isAnyObject() const {
      96       114119106 :         return data == JSVAL_TYPE_OBJECT;
      97                 :     }
      98                 : 
      99       232473362 :     bool isUnknown() const {
     100       232473362 :         return data == JSVAL_TYPE_UNKNOWN;
     101                 :     }
     102                 : 
     103                 :     /* Accessors for types that are either JSObject or TypeObject. */
     104                 : 
     105        60665460 :     bool isObject() const {
     106        60665460 :         JS_ASSERT(!isAnyObject() && !isUnknown());
     107        60665460 :         return data > JSVAL_TYPE_UNKNOWN;
     108                 :     }
     109                 : 
     110        43244990 :     TypeObjectKey *objectKey() const {
     111        43244990 :         JS_ASSERT(isObject());
     112        43244990 :         return (TypeObjectKey *) data;
     113                 :     }
     114                 : 
     115                 :     /* Accessors for JSObject types */
     116                 : 
     117        10738758 :     bool isSingleObject() const {
     118        10738758 :         return isObject() && !!(data & 1);
     119                 :     }
     120                 : 
     121         3410465 :     JSObject *singleObject() const {
     122         3410465 :         JS_ASSERT(isSingleObject());
     123         3410465 :         return (JSObject *) (data ^ 1);
     124                 :     }
     125                 : 
     126                 :     /* Accessors for TypeObject types */
     127                 : 
     128         5203490 :     bool isTypeObject() const {
     129         5203490 :         return isObject() && !(data & 1);
     130                 :     }
     131                 : 
     132         4235063 :     TypeObject *typeObject() const {
     133         4235063 :         JS_ASSERT(isTypeObject());
     134         4235063 :         return (TypeObject *) data;
     135                 :     }
     136                 : 
     137         3438510 :     bool operator == (Type o) const { return data == o.data; }
     138            6865 :     bool operator != (Type o) const { return data != o.data; }
     139                 : 
     140          802337 :     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
     141          327117 :     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
     142          395397 :     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
     143          473174 :     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
     144        12708585 :     static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
     145          719578 :     static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
     146            1758 :     static inline Type LazyArgsType()  { return Type(JSVAL_TYPE_MAGIC); }
     147          389409 :     static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
     148         2570680 :     static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
     149                 : 
     150       115764817 :     static inline Type PrimitiveType(JSValueType type) {
     151       115764817 :         JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
     152       115764817 :         return Type(type);
     153                 :     }
     154                 : 
     155                 :     static inline Type ObjectType(JSObject *obj);
     156                 :     static inline Type ObjectType(TypeObject *obj);
     157                 :     static inline Type ObjectType(TypeObjectKey *obj);
     158                 : };
     159                 : 
     160                 : /* Get the type of a jsval, or zero for an unknown special value. */
     161                 : inline Type GetValueType(JSContext *cx, const Value &val);
     162                 : 
     163                 : /*
     164                 :  * Type inference memory management overview.
     165                 :  *
     166                 :  * Inference constructs a global web of constraints relating the contents of
     167                 :  * type sets particular to various scripts and type objects within a
     168                 :  * compartment. This data can consume a significant amount of memory, and to
     169                 :  * avoid this building up we try to clear it with some regularity. On each GC
     170                 :  * which occurs while we are not actively working with inference or other
     171                 :  * analysis information, we clear out all generated constraints, all type sets
     172                 :  * describing stack types within scripts, and (normally) all data describing
     173                 :  * type objects for particular JS objects (see the lazy type objects overview
     174                 :  * below). JIT code depends on this data and is cleared as well.
     175                 :  *
     176                 :  * All this data is allocated into compartment->pool. Some type inference data
     177                 :  * lives across GCs: type sets for scripts and non-singleton type objects, and
     178                 :  * propeties for such type objects. This data is also allocated into
     179                 :  * compartment->pool, but everything still live is copied to a new arena on GC.
     180                 :  */
     181                 : 
     182                 : /*
     183                 :  * A constraint which listens to additions to a type set and propagates those
     184                 :  * changes to other type sets.
     185                 :  */
     186                 : class TypeConstraint
     187                 : {
     188                 : public:
     189                 : #ifdef DEBUG
     190                 :     const char *kind_;
     191         4604451 :     const char *kind() const { return kind_; }
     192                 : #else
     193                 :     const char *kind() const { return NULL; }
     194                 : #endif
     195                 : 
     196                 :     /* Next constraint listening to the same type set. */
     197                 :     TypeConstraint *next;
     198                 : 
     199         4604451 :     TypeConstraint(const char *kind)
     200         4604451 :         : next(NULL)
     201                 :     {
     202                 : #ifdef DEBUG
     203         4604451 :         this->kind_ = kind;
     204                 : #endif
     205         4604451 :     }
     206                 : 
     207                 :     /* Register a new type for the set this constraint is listening to. */
     208                 :     virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
     209                 : 
     210                 :     /*
     211                 :      * For constraints attached to an object property's type set, mark the
     212                 :      * property as having been configured or received an own property.
     213                 :      */
     214            6597 :     virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
     215                 : 
     216                 :     /*
     217                 :      * For constraints attached to the JSID_EMPTY type set on an object, mark a
     218                 :      * change in one of the object's dynamic property flags. If force is set,
     219                 :      * recompilation is always triggered.
     220                 :      */
     221               0 :     virtual void newObjectState(JSContext *cx, TypeObject *object, bool force) {}
     222                 : };
     223                 : 
     224                 : /* Flags and other state stored in TypeSet::flags */
     225                 : enum {
     226                 :     TYPE_FLAG_UNDEFINED =  0x1,
     227                 :     TYPE_FLAG_NULL      =  0x2,
     228                 :     TYPE_FLAG_BOOLEAN   =  0x4,
     229                 :     TYPE_FLAG_INT32     =  0x8,
     230                 :     TYPE_FLAG_DOUBLE    = 0x10,
     231                 :     TYPE_FLAG_STRING    = 0x20,
     232                 :     TYPE_FLAG_LAZYARGS  = 0x40,
     233                 :     TYPE_FLAG_ANYOBJECT = 0x80,
     234                 : 
     235                 :     /* Mask/shift for the number of objects in objectSet */
     236                 :     TYPE_FLAG_OBJECT_COUNT_MASK   = 0xff00,
     237                 :     TYPE_FLAG_OBJECT_COUNT_SHIFT  = 8,
     238                 :     TYPE_FLAG_OBJECT_COUNT_LIMIT  =
     239                 :         TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
     240                 : 
     241                 :     /* Whether the contents of this type set are totally unknown. */
     242                 :     TYPE_FLAG_UNKNOWN             = 0x00010000,
     243                 : 
     244                 :     /* Mask of normal type flags on a type set. */
     245                 :     TYPE_FLAG_BASE_MASK           = 0x000100ff,
     246                 : 
     247                 :     /* Flags for type sets which are on object properties. */
     248                 : 
     249                 :     /*
     250                 :      * Whether there are subset constraints propagating the possible types
     251                 :      * for this property inherited from the object's prototypes. Reset on GC.
     252                 :      */
     253                 :     TYPE_FLAG_PROPAGATED_PROPERTY = 0x00020000,
     254                 : 
     255                 :     /* Whether this property has ever been directly written. */
     256                 :     TYPE_FLAG_OWN_PROPERTY        = 0x00040000,
     257                 : 
     258                 :     /*
     259                 :      * Whether the property has ever been deleted or reconfigured to behave
     260                 :      * differently from a normal native property (e.g. made non-writable or
     261                 :      * given a scripted getter or setter).
     262                 :      */
     263                 :     TYPE_FLAG_CONFIGURED_PROPERTY = 0x00080000,
     264                 : 
     265                 :     /*
     266                 :      * Whether the property is definitely in a particular inline slot on all
     267                 :      * objects from which it has not been deleted or reconfigured. Implies
     268                 :      * OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
     269                 :      */
     270                 :     TYPE_FLAG_DEFINITE_PROPERTY   = 0x00100000,
     271                 : 
     272                 :     /* If the property is definite, mask and shift storing the slot. */
     273                 :     TYPE_FLAG_DEFINITE_MASK       = 0x0f000000,
     274                 :     TYPE_FLAG_DEFINITE_SHIFT      = 24
     275                 : };
     276                 : typedef uint32_t TypeFlags;
     277                 : 
     278                 : /* Flags and other state stored in TypeObject::flags */
     279                 : enum {
     280                 :     /* Objects with this type are functions. */
     281                 :     OBJECT_FLAG_FUNCTION              = 0x1,
     282                 : 
     283                 :     /* If set, newScript information should not be installed on this object. */
     284                 :     OBJECT_FLAG_NEW_SCRIPT_CLEARED    = 0x2,
     285                 : 
     286                 :     /*
     287                 :      * If set, type constraints covering the correctness of the newScript
     288                 :      * definite properties need to be regenerated before compiling any jitcode
     289                 :      * which depends on this information.
     290                 :      */
     291                 :     OBJECT_FLAG_NEW_SCRIPT_REGENERATE = 0x4,
     292                 : 
     293                 :     /*
     294                 :      * Whether we have ensured all type sets in the compartment contain
     295                 :      * ANYOBJECT instead of this object.
     296                 :      */
     297                 :     OBJECT_FLAG_SETS_MARKED_UNKNOWN   = 0x8,
     298                 : 
     299                 :     /* Mask/shift for the number of properties in propertySet */
     300                 :     OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff0,
     301                 :     OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 4,
     302                 :     OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
     303                 :         OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
     304                 : 
     305                 :     /*
     306                 :      * Some objects are not dense arrays, or are dense arrays whose length
     307                 :      * property does not fit in an int32_t.
     308                 :      */
     309                 :     OBJECT_FLAG_NON_DENSE_ARRAY       = 0x00010000,
     310                 : 
     311                 :     /* Whether any objects this represents are not packed arrays. */
     312                 :     OBJECT_FLAG_NON_PACKED_ARRAY      = 0x00020000,
     313                 : 
     314                 :     /* Whether any objects this represents are not typed arrays. */
     315                 :     OBJECT_FLAG_NON_TYPED_ARRAY       = 0x00040000,
     316                 : 
     317                 :     /* Whether any represented script has had arguments objects created. */
     318                 :     OBJECT_FLAG_CREATED_ARGUMENTS     = 0x00080000,
     319                 : 
     320                 :     /* Whether any represented script is considered uninlineable. */
     321                 :     OBJECT_FLAG_UNINLINEABLE          = 0x00100000,
     322                 : 
     323                 :     /* Whether any objects have an equality hook. */
     324                 :     OBJECT_FLAG_SPECIAL_EQUALITY      = 0x00200000,
     325                 : 
     326                 :     /* Whether any objects have been iterated over. */
     327                 :     OBJECT_FLAG_ITERATED              = 0x00400000,
     328                 : 
     329                 :     /* Outer function which has been marked reentrant. */
     330                 :     OBJECT_FLAG_REENTRANT_FUNCTION    = 0x00800000,
     331                 : 
     332                 :     /* For a global object, whether flags were set on the RegExpStatics. */
     333                 :     OBJECT_FLAG_REGEXP_FLAGS_SET      = 0x01000000,
     334                 : 
     335                 :     /* Flags which indicate dynamic properties of represented objects. */
     336                 :     OBJECT_FLAG_DYNAMIC_MASK          = 0x01ff0000,
     337                 : 
     338                 :     /*
     339                 :      * Whether all properties of this object are considered unknown.
     340                 :      * If set, all flags in DYNAMIC_MASK will also be set.
     341                 :      */
     342                 :     OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x80000000,
     343                 : 
     344                 :     /* Mask for objects created with unknown properties. */
     345                 :     OBJECT_FLAG_UNKNOWN_MASK =
     346                 :         OBJECT_FLAG_DYNAMIC_MASK
     347                 :       | OBJECT_FLAG_UNKNOWN_PROPERTIES
     348                 :       | OBJECT_FLAG_SETS_MARKED_UNKNOWN
     349                 : };
     350                 : typedef uint32_t TypeObjectFlags;
     351                 : 
     352                 : /* Information about the set of types associated with an lvalue. */
     353                 : class TypeSet
     354                 : {
     355                 :     /* Flags for this type set. */
     356                 :     TypeFlags flags;
     357                 : 
     358                 :     /* Possible objects this type set can represent. */
     359                 :     TypeObjectKey **objectSet;
     360                 : 
     361                 :   public:
     362                 : 
     363                 :     /* Chain of constraints which propagate changes out from this type set. */
     364                 :     TypeConstraint *constraintList;
     365                 : 
     366          161781 :     TypeSet()
     367          161781 :         : flags(0), objectSet(NULL), constraintList(NULL)
     368          161781 :     {}
     369                 : 
     370                 :     void print(JSContext *cx);
     371                 : 
     372                 :     inline void sweep(JSContext *cx, JSCompartment *compartment);
     373                 :     inline size_t computedSizeOfExcludingThis();
     374                 : 
     375                 :     /* Whether this set contains a specific type. */
     376                 :     inline bool hasType(Type type);
     377                 : 
     378         2000234 :     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
     379       179804967 :     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
     380         6652415 :     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
     381                 : 
     382                 :     bool empty() const { return !baseFlags() && !baseObjectCount(); }
     383                 : 
     384           36142 :     bool hasAnyFlag(TypeFlags flags) const {
     385           36142 :         JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
     386           36142 :         return !!(baseFlags() & flags);
     387                 :     }
     388                 : 
     389          223848 :     bool isOwnProperty(bool configurable) const {
     390          223848 :         return flags & (configurable ? TYPE_FLAG_CONFIGURED_PROPERTY : TYPE_FLAG_OWN_PROPERTY);
     391                 :     }
     392           47464 :     bool isDefiniteProperty() const { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
     393           11743 :     unsigned definiteSlot() const {
     394           11743 :         JS_ASSERT(isDefiniteProperty());
     395           11743 :         return flags >> TYPE_FLAG_DEFINITE_SHIFT;
     396                 :     }
     397                 : 
     398                 :     /*
     399                 :      * Add a type to this set, calling any constraint handlers if this is a new
     400                 :      * possible type.
     401                 :      */
     402                 :     inline void addType(JSContext *cx, Type type);
     403                 : 
     404                 :     /* Mark this type set as representing an own property or configured property. */
     405                 :     inline void setOwnProperty(JSContext *cx, bool configured);
     406                 : 
     407                 :     /*
     408                 :      * Iterate through the objects in this set. getObjectCount overapproximates
     409                 :      * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
     410                 :      * may return NULL.
     411                 :      */
     412                 :     inline unsigned getObjectCount();
     413                 :     inline TypeObjectKey *getObject(unsigned i);
     414                 :     inline JSObject *getSingleObject(unsigned i);
     415                 :     inline TypeObject *getTypeObject(unsigned i);
     416                 : 
     417                 :     void setOwnProperty(bool configurable) {
     418                 :         flags |= TYPE_FLAG_OWN_PROPERTY;
     419                 :         if (configurable)
     420                 :             flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
     421                 :     }
     422            7034 :     void setDefinite(unsigned slot) {
     423            7034 :         JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
     424            7034 :         flags |= TYPE_FLAG_DEFINITE_PROPERTY | (slot << TYPE_FLAG_DEFINITE_SHIFT);
     425            7034 :     }
     426                 : 
     427         1515025 :     bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
     428           91012 :     void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
     429                 : 
     430                 :     enum FilterKind {
     431                 :         FILTER_ALL_PRIMITIVES,
     432                 :         FILTER_NULL_VOID,
     433                 :         FILTER_VOID
     434                 :     };
     435                 : 
     436                 :     /* Add specific kinds of constraints to this set. */
     437                 :     inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
     438                 :     void addSubset(JSContext *cx, TypeSet *target);
     439                 :     void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
     440                 :                         TypeSet *target, jsid id);
     441                 :     void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
     442                 :                         TypeSet *target, jsid id);
     443                 :     void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
     444                 :     void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
     445                 :                        TypeSet *objectTypes, TypeSet *valueTypes);
     446                 :     void addCall(JSContext *cx, TypeCallsite *site);
     447                 :     void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
     448                 :                   TypeSet *target, TypeSet *other = NULL);
     449                 :     void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
     450                 :     void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
     451                 :                           Type type, TypeSet *types = NULL);
     452                 :     void addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter);
     453                 :     void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
     454                 :     void addLazyArguments(JSContext *cx, TypeSet *target);
     455                 : 
     456                 :     /*
     457                 :      * Make an type set with the specified debugging name, not embedded in
     458                 :      * another structure.
     459                 :      */
     460                 :     static TypeSet *make(JSContext *cx, const char *name);
     461                 : 
     462                 :     /*
     463                 :      * Methods for JIT compilation. If a script is currently being compiled
     464                 :      * (see AutoEnterCompilation) these will add constraints ensuring that if
     465                 :      * the return value change in the future due to new type information, the
     466                 :      * currently compiled script will be marked for recompilation.
     467                 :      */
     468                 : 
     469                 :     /* Completely freeze the contents of this type set. */
     470                 :     void addFreeze(JSContext *cx);
     471                 : 
     472                 :     /* Get any type tag which all values in this set must have. */
     473                 :     JSValueType getKnownTypeTag(JSContext *cx);
     474                 : 
     475           39809 :     bool isLazyArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
     476                 : 
     477                 :     /* Whether the type set or a particular object has any of a set of flags. */
     478                 :     bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
     479                 :     static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
     480                 : 
     481                 :     /*
     482                 :      * Watch for a generic object state change on a type object. This currently
     483                 :      * includes reallocations of slot pointers for global objects, and changes
     484                 :      * to newScript data on types.
     485                 :      */
     486                 :     static void WatchObjectStateChange(JSContext *cx, TypeObject *object);
     487                 : 
     488                 :     /*
     489                 :      * For type sets on a property, return true if the property has any 'own'
     490                 :      * values assigned. If configurable is set, return 'true' if the property
     491                 :      * has additionally been reconfigured as non-configurable, non-enumerable
     492                 :      * or non-writable (this only applies to properties that have changed after
     493                 :      * having been created, not to e.g. properties non-writable on creation).
     494                 :      */
     495                 :     bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
     496                 : 
     497                 :     /* Get whether this type set is non-empty. */
     498                 :     bool knownNonEmpty(JSContext *cx);
     499                 : 
     500                 :     /* Get whether this type set is known to be a subset of other. */
     501                 :     bool knownSubset(JSContext *cx, TypeSet *other);
     502                 : 
     503                 :     /*
     504                 :      * Get the typed array type of all objects in this set. Returns
     505                 :      * TypedArray::TYPE_MAX if the set contains different array types.
     506                 :      */
     507                 :     int getTypedArrayType(JSContext *cx);
     508                 : 
     509                 :     /* Get the single value which can appear in this type set, otherwise NULL. */
     510                 :     JSObject *getSingleton(JSContext *cx, bool freeze = true);
     511                 : 
     512                 :     /* Whether all objects in this set are parented to a particular global. */
     513                 :     bool hasGlobalObject(JSContext *cx, JSObject *global);
     514                 : 
     515                 :     inline void clearObjects();
     516                 : 
     517                 :     /*
     518                 :      * Whether a location with this TypeSet needs a write barrier (i.e., whether
     519                 :      * it can hold GC things). The type set is frozen if no barrier is needed.
     520                 :      */
     521                 :     bool needsBarrier(JSContext *cx);
     522                 : 
     523                 :     /* The type set is frozen if no barrier is needed. */
     524                 :     bool propertyNeedsBarrier(JSContext *cx, jsid id);
     525                 : 
     526                 :   private:
     527        56454418 :     uint32_t baseObjectCount() const {
     528        56454418 :         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     529                 :     }
     530                 :     inline void setBaseObjectCount(uint32_t count);
     531                 : };
     532                 : 
     533                 : /*
     534                 :  * Handler which persists information about dynamic types pushed within a
     535                 :  * script which can affect its behavior and are not covered by JOF_TYPESET ops,
     536                 :  * such as integer operations which overflow to a double. These persist across
     537                 :  * GCs, and are used to re-seed script types when they are reanalyzed.
     538                 :  */
     539                 : struct TypeResult
     540            2798 : {
     541                 :     uint32_t offset;
     542                 :     Type type;
     543                 :     TypeResult *next;
     544                 : 
     545            2798 :     TypeResult(uint32_t offset, Type type)
     546            2798 :         : offset(offset), type(type), next(NULL)
     547            2798 :     {}
     548                 : };
     549                 : 
     550                 : /*
     551                 :  * Type barriers overview.
     552                 :  *
     553                 :  * Type barriers are a technique for using dynamic type information to improve
     554                 :  * the inferred types within scripts. At certain opcodes --- those with the
     555                 :  * JOF_TYPESET format --- we will construct a type set storing the set of types
     556                 :  * which we have observed to be pushed at that opcode, and will only use those
     557                 :  * observed types when doing propagation downstream from the bytecode. For
     558                 :  * example, in the following script:
     559                 :  *
     560                 :  * function foo(x) {
     561                 :  *   return x.f + 10;
     562                 :  * }
     563                 :  *
     564                 :  * Suppose we know the type of 'x' and that the type of its 'f' property is
     565                 :  * either an int or float. To account for all possible behaviors statically,
     566                 :  * we would mark the result of the 'x.f' access as an int or float, as well
     567                 :  * as the result of the addition and the return value of foo (and everywhere
     568                 :  * the result of 'foo' is used). When dealing with polymorphic code, this is
     569                 :  * undesirable behavior --- the type imprecision surrounding the polymorphism
     570                 :  * will tend to leak to many places in the program.
     571                 :  *
     572                 :  * Instead, we will keep track of the types that have been dynamically observed
     573                 :  * to have been produced by the 'x.f', and only use those observed types
     574                 :  * downstream from the access. If the 'x.f' has only ever produced integers,
     575                 :  * we will treat its result as an integer and mark the result of foo as an
     576                 :  * integer.
     577                 :  *
     578                 :  * The set of observed types will be a subset of the set of possible types,
     579                 :  * and if the two sets are different, a type barriers will be added at the
     580                 :  * bytecode which checks the dynamic result every time the bytecode executes
     581                 :  * and makes sure it is in the set of observed types. If it is not, that
     582                 :  * observed set is updated, and the new type information is automatically
     583                 :  * propagated along the already-generated type constraints to the places
     584                 :  * where the result of the bytecode is used.
     585                 :  *
     586                 :  * Observing new types at a bytecode removes type barriers at the bytecode
     587                 :  * (this removal happens lazily, see ScriptAnalysis::pruneTypeBarriers), and if
     588                 :  * all type barriers at a bytecode are removed --- the set of observed types
     589                 :  * grows to match the set of possible types --- then the result of the bytecode
     590                 :  * no longer needs to be dynamically checked (unless the set of possible types
     591                 :  * grows, triggering the generation of new type barriers).
     592                 :  *
     593                 :  * Barriers are only relevant for accesses on properties whose types inference
     594                 :  * actually tracks (see propertySet comment under TypeObject). Accesses on
     595                 :  * other properties may be able to produce additional unobserved types even
     596                 :  * without a barrier present, and can only be compiled to jitcode with special
     597                 :  * knowledge of the property in question (e.g. for lengths of arrays, or
     598                 :  * elements of typed arrays).
     599                 :  */
     600                 : 
     601                 : /*
     602                 :  * Barrier introduced at some bytecode. These are added when, during inference,
     603                 :  * we block a type from being propagated as would normally be done for a subset
     604                 :  * constraint. The propagation is technically possible, but we suspect it will
     605                 :  * not happen dynamically and this type needs to be watched for. These are only
     606                 :  * added at reads of properties and at scripted call sites.
     607                 :  */
     608                 : struct TypeBarrier
     609                 : {
     610                 :     /* Next barrier on the same bytecode. */
     611                 :     TypeBarrier *next;
     612                 : 
     613                 :     /* Target type set into which propagation was blocked. */
     614                 :     TypeSet *target;
     615                 : 
     616                 :     /*
     617                 :      * Type which was not added to the target. If target ends up containing the
     618                 :      * type somehow, this barrier can be removed.
     619                 :      */
     620                 :     Type type;
     621                 : 
     622                 :     /*
     623                 :      * If specified, this barrier can be removed if object has a non-undefined
     624                 :      * value in property id.
     625                 :      */
     626                 :     JSObject *singleton;
     627                 :     jsid singletonId;
     628                 : 
     629          545901 :     TypeBarrier(TypeSet *target, Type type, JSObject *singleton, jsid singletonId)
     630                 :         : next(NULL), target(target), type(type),
     631          545901 :           singleton(singleton), singletonId(singletonId)
     632          545901 :     {}
     633                 : };
     634                 : 
     635                 : /* Type information about a property. */
     636                 : struct Property
     637            4780 : {
     638                 :     /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
     639                 :     HeapId id;
     640                 : 
     641                 :     /* Possible types for this property, including types inherited from prototypes. */
     642                 :     TypeSet types;
     643                 : 
     644                 :     inline Property(jsid id);
     645                 :     inline Property(const Property &o);
     646                 : 
     647          418105 :     static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
     648        26652713 :     static jsid getKey(Property *p) { return p->id; }
     649                 : };
     650                 : 
     651                 : /*
     652                 :  * Information attached to a TypeObject if it is always constructed using 'new'
     653                 :  * on a particular script. This is used to manage state related to the definite
     654                 :  * properties on the type object: these definite properties depend on type
     655                 :  * information which could change as the script executes (e.g. a scripted
     656                 :  * setter is added to a prototype object), and we need to ensure both that the
     657                 :  * appropriate type constraints are in place when necessary, and that we can
     658                 :  * remove the definite property information and repair the JS stack if the
     659                 :  * constraints are violated.
     660                 :  */
     661                 : struct TypeNewScript
     662                 : {
     663                 :     HeapPtrFunction fun;
     664                 : 
     665                 :     /* Allocation kind to use for newly constructed objects. */
     666                 :     gc::AllocKind allocKind;
     667                 : 
     668                 :     /*
     669                 :      * Shape to use for newly constructed objects. Reflects all definite
     670                 :      * properties the object will have.
     671                 :      */
     672                 :     HeapPtrShape  shape;
     673                 : 
     674                 :     /*
     675                 :      * Order in which properties become initialized. We need this in case a
     676                 :      * scripted setter is added to one of the object's prototypes while it is
     677                 :      * in the middle of being initialized, so we can walk the stack and fixup
     678                 :      * any objects which look for in-progress objects which were prematurely
     679                 :      * set with their final shape. Initialization can traverse stack frames,
     680                 :      * in which case FRAME_PUSH/FRAME_POP are used.
     681                 :      */
     682            2977 :     struct Initializer {
     683                 :         enum Kind {
     684                 :             SETPROP,
     685                 :             FRAME_PUSH,
     686                 :             FRAME_POP,
     687                 :             DONE
     688                 :         } kind;
     689                 :         uint32_t offset;
     690            1675 :         Initializer(Kind kind, uint32_t offset)
     691            1675 :           : kind(kind), offset(offset)
     692            1675 :         {}
     693                 :     };
     694                 :     Initializer *initializerList;
     695                 : 
     696                 :     static inline void writeBarrierPre(TypeNewScript *newScript);
     697                 :     static inline void writeBarrierPost(TypeNewScript *newScript, void *addr);
     698                 : };
     699                 : 
     700                 : /*
     701                 :  * Lazy type objects overview.
     702                 :  *
     703                 :  * Type objects which represent at most one JS object are constructed lazily.
     704                 :  * These include types for native functions, standard classes, scripted
     705                 :  * functions defined at the top level of global/eval scripts, and in some
     706                 :  * other cases. Typical web workloads often create many windows (and many
     707                 :  * copies of standard natives) and many scripts, with comparatively few
     708                 :  * non-singleton types.
     709                 :  *
     710                 :  * We can recover the type information for the object from examining it,
     711                 :  * so don't normally track the possible types of its properties as it is
     712                 :  * updated. Property type sets for the object are only constructed when an
     713                 :  * analyzed script attaches constraints to it: the script is querying that
     714                 :  * property off the object or another which delegates to it, and the analysis
     715                 :  * information is sensitive to changes in the property's type. Future changes
     716                 :  * to the property (whether those uncovered by analysis or those occurring
     717                 :  * in the VM) will treat these properties like those of any other type object.
     718                 :  *
     719                 :  * When a GC occurs, we wipe out all analysis information for all the
     720                 :  * compartment's scripts, so can destroy all properties on singleton type
     721                 :  * objects at the same time. If there is no reference on the stack to the
     722                 :  * type object itself, the type object is also destroyed, and the JS object
     723                 :  * reverts to having a lazy type.
     724                 :  */
     725                 : 
     726                 : /* Type information about an object accessed by a script. */
     727                 : struct TypeObject : gc::Cell
     728                 : {
     729                 :     /* Prototype shared by objects using this type. */
     730                 :     HeapPtrObject proto;
     731                 : 
     732                 :     /*
     733                 :      * Whether there is a singleton JS object with this type. That JS object
     734                 :      * must appear in type sets instead of this; we include the back reference
     735                 :      * here to allow reverting the JS object to a lazy type.
     736                 :      */
     737                 :     HeapPtrObject singleton;
     738                 : 
     739                 :     /*
     740                 :      * Value held by singleton if this is a standin type for a singleton JS
     741                 :      * object whose type has not been constructed yet.
     742                 :      */
     743                 :     static const size_t LAZY_SINGLETON = 1;
     744       187797330 :     bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
     745                 : 
     746                 :     /* Flags for this object. */
     747                 :     TypeObjectFlags flags;
     748                 : 
     749                 :     /*
     750                 :      * Estimate of the contribution of this object to the type sets it appears in.
     751                 :      * This is the sum of the sizes of those sets at the point when the object
     752                 :      * was added.
     753                 :      *
     754                 :      * When the contribution exceeds the CONTRIBUTION_LIMIT, any type sets the
     755                 :      * object is added to are instead marked as unknown. If we get to this point
     756                 :      * we are probably not adding types which will let us do meaningful optimization
     757                 :      * later, and we want to ensure in such cases that our time/space complexity
     758                 :      * is linear, not worst-case cubic as it would otherwise be.
     759                 :      */
     760                 :     uint32_t contribution;
     761                 :     static const uint32_t CONTRIBUTION_LIMIT = 2000;
     762                 : 
     763                 :     /*
     764                 :      * If non-NULL, objects of this type have always been constructed using
     765                 :      * 'new' on the specified script, which adds some number of properties to
     766                 :      * the object in a definite order before the object escapes.
     767                 :      */
     768                 :     HeapPtr<TypeNewScript> newScript;
     769                 : 
     770                 :     /*
     771                 :      * Properties of this object. This may contain JSID_VOID, representing the
     772                 :      * types of all integer indexes of the object, and/or JSID_EMPTY, holding
     773                 :      * constraints listening to changes to the object's state.
     774                 :      *
     775                 :      * The type sets in the properties of a type object describe the possible
     776                 :      * values that can be read out of that property in actual JS objects.
     777                 :      * Properties only account for native properties (those with a slot and no
     778                 :      * specialized getter hook) and the elements of dense arrays. For accesses
     779                 :      * on such properties, the correspondence is as follows:
     780                 :      *
     781                 :      * 1. If the type has unknownProperties(), the possible properties and
     782                 :      *    value types for associated JSObjects are unknown.
     783                 :      *
     784                 :      * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
     785                 :      *    which is a property in obj, before obj->getProperty(id) the property
     786                 :      *    in type for id must reflect the result of the getProperty.
     787                 :      *
     788                 :      *    There is an exception for properties of singleton JS objects which
     789                 :      *    are undefined at the point where the property was (lazily) generated.
     790                 :      *    In such cases the property type set will remain empty, and the
     791                 :      *    'undefined' type will only be added after a subsequent assignment or
     792                 :      *    deletion. After these properties have been assigned a defined value,
     793                 :      *    the only way they can become undefined again is after such an assign
     794                 :      *    or deletion.
     795                 :      *
     796                 :      * We establish these by using write barriers on calls to setProperty and
     797                 :      * defineProperty which are on native properties, and by using the inference
     798                 :      * analysis to determine the side effects of code which is JIT-compiled.
     799                 :      */
     800                 :     Property **propertySet;
     801                 : 
     802                 :     /* If this is an interpreted function, the function object. */
     803                 :     HeapPtrFunction interpretedFunction;
     804                 : 
     805                 : #if JS_BITS_PER_WORD == 32
     806                 :     void *padding;
     807                 : #endif
     808                 : 
     809                 :     inline TypeObject(JSObject *proto, bool isFunction, bool unknown);
     810                 : 
     811           13763 :     bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
     812                 : 
     813          469858 :     bool hasAnyFlags(TypeObjectFlags flags) {
     814          469858 :         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
     815          469858 :         return !!(this->flags & flags);
     816                 :     }
     817         9326350 :     bool hasAllFlags(TypeObjectFlags flags) {
     818         9326350 :         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
     819         9326350 :         return (this->flags & flags) == flags;
     820                 :     }
     821                 : 
     822        54313388 :     bool unknownProperties() {
     823         7972369 :         JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
     824        62285757 :                      hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
     825        54313388 :         return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
     826                 :     }
     827                 : 
     828                 :     /*
     829                 :      * Get or create a property of this object. Only call this for properties which
     830                 :      * a script accesses explicitly. 'assign' indicates whether this is for an
     831                 :      * assignment, and the own types of the property will be used instead of
     832                 :      * aggregate types.
     833                 :      */
     834                 :     inline TypeSet *getProperty(JSContext *cx, jsid id, bool assign);
     835                 : 
     836                 :     /* Get a property only if it already exists. */
     837                 :     inline TypeSet *maybeGetProperty(JSContext *cx, jsid id);
     838                 : 
     839                 :     inline unsigned getPropertyCount();
     840                 :     inline Property *getProperty(unsigned i);
     841                 : 
     842                 :     /* Set flags on this object which are implied by the specified key. */
     843                 :     inline void setFlagsFromKey(JSContext *cx, JSProtoKey kind);
     844                 : 
     845                 :     /*
     846                 :      * Get the global object which all objects of this type are parented to,
     847                 :      * or NULL if there is none known.
     848                 :      */
     849                 :     inline JSObject *getGlobal();
     850                 : 
     851                 :     /* Helpers */
     852                 : 
     853                 :     bool addProperty(JSContext *cx, jsid id, Property **pprop);
     854                 :     bool addDefiniteProperties(JSContext *cx, JSObject *obj);
     855                 :     bool matchDefiniteProperties(JSObject *obj);
     856                 :     void addPrototype(JSContext *cx, TypeObject *proto);
     857                 :     void addPropertyType(JSContext *cx, jsid id, Type type);
     858                 :     void addPropertyType(JSContext *cx, jsid id, const Value &value);
     859                 :     void addPropertyType(JSContext *cx, const char *name, Type type);
     860                 :     void addPropertyType(JSContext *cx, const char *name, const Value &value);
     861                 :     void markPropertyConfigured(JSContext *cx, jsid id);
     862                 :     void markStateChange(JSContext *cx);
     863                 :     void setFlags(JSContext *cx, TypeObjectFlags flags);
     864                 :     void markUnknown(JSContext *cx);
     865                 :     void clearNewScript(JSContext *cx);
     866                 :     void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
     867                 : 
     868                 :     void print(JSContext *cx);
     869                 : 
     870                 :     inline void clearProperties();
     871                 :     inline void sweep(JSContext *cx);
     872                 : 
     873                 :     inline size_t computedSizeOfExcludingThis();
     874                 : 
     875                 :     void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf);
     876                 : 
     877                 :     /*
     878                 :      * Type objects don't have explicit finalizers. Memory owned by a type
     879                 :      * object pending deletion is released when weak references are sweeped
     880                 :      * from all the compartment's type objects.
     881                 :      */
     882          670986 :     void finalize(JSContext *cx, bool background) {}
     883                 : 
     884                 :     static inline void writeBarrierPre(TypeObject *type);
     885                 :     static inline void writeBarrierPost(TypeObject *type, void *addr);
     886                 :     static inline void readBarrier(TypeObject *type);
     887                 : 
     888                 :     static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
     889                 : 
     890                 :   private:
     891                 :     inline uint32_t basePropertyCount() const;
     892                 :     inline void setBasePropertyCount(uint32_t count);
     893                 : 
     894                 :     static void staticAsserts() {
     895                 :         JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto));
     896                 :     }
     897                 : };
     898                 : 
     899                 : /*
     900                 :  * Entries for the per-compartment set of type objects which are the default
     901                 :  * 'new' or the lazy types of some prototype.
     902                 :  */
     903                 : struct TypeObjectEntry
     904                 : {
     905                 :     typedef JSObject *Lookup;
     906                 : 
     907                 :     static inline HashNumber hash(JSObject *base);
     908                 :     static inline bool match(TypeObject *key, JSObject *lookup);
     909                 : };
     910                 : typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
     911                 : 
     912                 : /*
     913                 :  * Call to mark a script's arguments as having been created, recompile any
     914                 :  * dependencies and walk the stack if necessary to fix any lazy arguments.
     915                 :  */
     916                 : extern void
     917                 : MarkArgumentsCreated(JSContext *cx, JSScript *script);
     918                 : 
     919                 : /* Whether to use a new type object when calling 'new' at script/pc. */
     920                 : bool
     921                 : UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
     922                 : 
     923                 : /*
     924                 :  * Whether Array.prototype, or an object on its proto chain, has an
     925                 :  * indexed property.
     926                 :  */
     927                 : bool
     928                 : ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
     929                 : 
     930                 : /*
     931                 :  * Type information about a callsite. this is separated from the bytecode
     932                 :  * information itself so we can handle higher order functions not called
     933                 :  * directly via a bytecode.
     934                 :  */
     935                 : struct TypeCallsite
     936                 : {
     937                 :     JSScript *script;
     938                 :     jsbytecode *pc;
     939                 : 
     940                 :     /* Whether this is a 'NEW' call. */
     941                 :     bool isNew;
     942                 : 
     943                 :     /* Types of each argument to the call. */
     944                 :     TypeSet **argumentTypes;
     945                 :     unsigned argumentCount;
     946                 : 
     947                 :     /* Types of the this variable. */
     948                 :     TypeSet *thisTypes;
     949                 : 
     950                 :     /* Type set receiving the return value of this call. */
     951                 :     TypeSet *returnTypes;
     952                 : 
     953                 :     inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
     954                 :                         bool isNew, unsigned argumentCount);
     955                 : };
     956                 : 
     957                 : /*
     958                 :  * Information attached to outer and inner function scripts nested in one
     959                 :  * another for tracking the reentrance state for outer functions. This state is
     960                 :  * used to generate fast accesses to the args and vars of the outer function.
     961                 :  *
     962                 :  * A function is non-reentrant if, at any point in time, only the most recent
     963                 :  * activation (i.e. call object) is live. An activation is live if either the
     964                 :  * activation is on the stack, or a transitive inner function parented to the
     965                 :  * activation is on the stack.
     966                 :  *
     967                 :  * Because inner functions can be (and, quite often, are) stored in object
     968                 :  * properties and it is difficult to build a fast and robust escape analysis
     969                 :  * to cope with such flow, we detect reentrance dynamically. For the outer
     970                 :  * function, we keep track of the call object for the most recent activation,
     971                 :  * and the number of frames for the function and its inner functions which are
     972                 :  * on the stack.
     973                 :  *
     974                 :  * If the outer function is called while frames associated with a previous
     975                 :  * activation are on the stack, the outer function is reentrant. If an inner
     976                 :  * function is called whose scope does not match the most recent activation,
     977                 :  * the outer function is reentrant.
     978                 :  *
     979                 :  * The situation gets trickier when there are several levels of nesting.
     980                 :  *
     981                 :  * function foo() {
     982                 :  *   var a;
     983                 :  *   function bar() {
     984                 :  *     var b;
     985                 :  *     function baz() { return a + b; }
     986                 :  *   }
     987                 :  * }
     988                 :  *
     989                 :  * At calls to 'baz', we don't want to do the scope check for the activations
     990                 :  * of both 'foo' and 'bar', but rather 'bar' only. For this to work, a call to
     991                 :  * 'baz' which is a reentrant call on 'foo' must also be a reentrant call on
     992                 :  * 'bar'. When 'foo' is called, we clear the most recent call object for 'bar'.
     993                 :  */
     994                 : struct TypeScriptNesting
     995                 : {
     996                 :     /*
     997                 :      * If this is an inner function, the outer function. If non-NULL, this will
     998                 :      * be the immediate nested parent of the script (even if that parent has
     999                 :      * been marked reentrant). May be NULL even if the script has a nested
    1000                 :      * parent, if NAME accesses cannot be tracked into the parent (either the
    1001                 :      * script extends its scope with eval() etc., or the parent can make new
    1002                 :      * scope chain objects with 'let' or 'with').
    1003                 :      */
    1004                 :     JSScript *parent;
    1005                 : 
    1006                 :     /* If this is an outer function, list of inner functions. */
    1007                 :     JSScript *children;
    1008                 : 
    1009                 :     /* Link for children list of parent. */
    1010                 :     JSScript *next;
    1011                 : 
    1012                 :     /* If this is an outer function, the most recent activation. */
    1013                 :     JSObject *activeCall;
    1014                 : 
    1015                 :     /*
    1016                 :      * If this is an outer function, pointers to the most recent activation's
    1017                 :      * arguments and variables arrays. These could be referring either to stack
    1018                 :      * values in activeCall's frame (if it has not finished yet) or to the
    1019                 :      * internal slots of activeCall (if the frame has finished). Pointers to
    1020                 :      * these fields can be embedded directly in JIT code (though remember to
    1021                 :      * use 'addDependency == true' when calling resolveNameAccess).
    1022                 :      */
    1023                 :     const Value *argArray;
    1024                 :     const Value *varArray;
    1025                 : 
    1026                 :     /* Number of frames for this function on the stack. */
    1027                 :     uint32_t activeFrames;
    1028                 : 
    1029            3709 :     TypeScriptNesting() { PodZero(this); }
    1030                 :     ~TypeScriptNesting();
    1031                 : };
    1032                 : 
    1033                 : /* Construct nesting information for script wrt its parent. */
    1034                 : bool CheckScriptNesting(JSContext *cx, JSScript *script);
    1035                 : 
    1036                 : /* Track nesting state when calling or finishing an outer/inner function. */
    1037                 : void NestingPrologue(JSContext *cx, StackFrame *fp);
    1038                 : void NestingEpilogue(StackFrame *fp);
    1039                 : 
    1040                 : /* Persistent type information for a script, retained across GCs. */
    1041                 : class TypeScript
    1042                 : {
    1043                 :     friend struct ::JSScript;
    1044                 : 
    1045                 :     /* Analysis information for the script, cleared on each GC. */
    1046                 :     analyze::ScriptAnalysis *analysis;
    1047                 : 
    1048                 :     /*
    1049                 :      * Information about the scope in which a script executes. This information
    1050                 :      * is not set until the script has executed at least once and SetScope
    1051                 :      * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
    1052                 :      */
    1053                 :     static const size_t GLOBAL_MISSING_SCOPE = 0x1;
    1054                 : 
    1055                 :     /* Global object for the script, if compileAndGo. */
    1056                 :     HeapPtr<GlobalObject> global;
    1057                 : 
    1058                 :   public:
    1059                 : 
    1060                 :     /* Nesting state for outer or inner function scripts. */
    1061                 :     TypeScriptNesting *nesting;
    1062                 : 
    1063                 :     /* Dynamic types generated at points within this script. */
    1064                 :     TypeResult *dynamicList;
    1065                 : 
    1066                 :     inline TypeScript();
    1067                 : 
    1068       186559869 :     bool hasScope() { return size_t(global.get()) != GLOBAL_MISSING_SCOPE; }
    1069                 : 
    1070                 :     /* Array of type type sets for variables and JOF_TYPESET ops. */
    1071        76039400 :     TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
    1072                 : 
    1073                 :     static inline unsigned NumTypeSets(JSScript *script);
    1074                 : 
    1075                 :     static bool SetScope(JSContext *cx, JSScript *script, JSObject *scope);
    1076                 : 
    1077                 :     static inline TypeSet *ReturnTypes(JSScript *script);
    1078                 :     static inline TypeSet *ThisTypes(JSScript *script);
    1079                 :     static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
    1080                 :     static inline TypeSet *LocalTypes(JSScript *script, unsigned i);
    1081                 : 
    1082                 :     /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
    1083                 :     static inline TypeSet *SlotTypes(JSScript *script, unsigned slot);
    1084                 : 
    1085                 : #ifdef DEBUG
    1086                 :     /* Check that correct types were inferred for the values pushed by this bytecode. */
    1087                 :     static void CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp);
    1088                 : #endif
    1089                 : 
    1090                 :     /* Get the default 'new' object for a given standard class, per the script's global. */
    1091                 :     static inline TypeObject *StandardType(JSContext *cx, JSScript *script, JSProtoKey kind);
    1092                 : 
    1093                 :     /* Get a type object for an allocation site in this script. */
    1094                 :     static inline TypeObject *InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JSProtoKey kind);
    1095                 : 
    1096                 :     /*
    1097                 :      * Monitor a bytecode pushing a value which is not accounted for by the
    1098                 :      * inference type constraints, such as integer overflow.
    1099                 :      */
    1100                 :     static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
    1101                 :     static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
    1102                 :     static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
    1103                 : 
    1104                 :     static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
    1105                 :     static inline void MonitorOverflow(JSContext *cx);
    1106                 :     static inline void MonitorString(JSContext *cx);
    1107                 :     static inline void MonitorUnknown(JSContext *cx);
    1108                 : 
    1109                 :     /*
    1110                 :      * Monitor a bytecode pushing any value. This must be called for any opcode
    1111                 :      * which is JOF_TYPESET, and where either the script has not been analyzed
    1112                 :      * by type inference or where the pc has type barriers. For simplicity, we
    1113                 :      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
    1114                 :      * and only look at barriers when generating JIT code for the script.
    1115                 :      */
    1116                 :     static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
    1117                 :                                const js::Value &val);
    1118                 :     static inline void Monitor(JSContext *cx, const js::Value &rval);
    1119                 : 
    1120                 :     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
    1121                 :     static inline void MonitorAssign(JSContext *cx, JSObject *obj, jsid id);
    1122                 : 
    1123                 :     /* Add a type for a variable in a script. */
    1124                 :     static inline void SetThis(JSContext *cx, JSScript *script, Type type);
    1125                 :     static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
    1126                 :     static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
    1127                 :     static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
    1128                 :     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
    1129                 :     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
    1130                 : 
    1131                 :     static void Sweep(JSContext *cx, JSScript *script);
    1132                 :     inline void trace(JSTracer *trc);
    1133                 :     void destroy();
    1134                 : };
    1135                 : 
    1136                 : struct ArrayTableKey;
    1137                 : typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
    1138                 : 
    1139                 : struct ObjectTableKey;
    1140                 : struct ObjectTableEntry;
    1141                 : typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
    1142                 : 
    1143                 : struct AllocationSiteKey;
    1144                 : typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
    1145                 : 
    1146                 : struct RecompileInfo
    1147           34484 : {
    1148                 :     JSScript *script;
    1149                 :     bool constructing:1;
    1150                 :     uint32_t chunkIndex:31;
    1151                 : 
    1152          259235 :     bool operator == (const RecompileInfo &o) const {
    1153          259235 :         return script == o.script && constructing == o.constructing && chunkIndex == o.chunkIndex;
    1154                 :     }
    1155                 : };
    1156                 : 
    1157                 : /* Type information for a compartment. */
    1158                 : struct TypeCompartment
    1159                 : {
    1160                 :     /* Whether type inference is enabled in this compartment. */
    1161                 :     bool inferenceEnabled;
    1162                 : 
    1163                 :     /* Number of scripts in this compartment. */
    1164                 :     unsigned scriptCount;
    1165                 : 
    1166                 :     /*
    1167                 :      * Bit set if all current types must be marked as unknown, and all scripts
    1168                 :      * recompiled. Caused by OOM failure within inference operations.
    1169                 :      */
    1170                 :     bool pendingNukeTypes;
    1171                 : 
    1172                 :     /* Pending recompilations to perform before execution of JIT code can resume. */
    1173                 :     Vector<RecompileInfo> *pendingRecompiles;
    1174                 : 
    1175                 :     /*
    1176                 :      * Number of recompilation events and inline frame expansions that have
    1177                 :      * occurred in this compartment. If these change, code should not count on
    1178                 :      * compiled code or the current stack being intact.
    1179                 :      */
    1180                 :     unsigned recompilations;
    1181                 :     unsigned frameExpansions;
    1182                 : 
    1183                 :     /*
    1184                 :      * Script currently being compiled. All constraints which look for type
    1185                 :      * changes inducing recompilation are keyed to this script. Note: script
    1186                 :      * compilation is not reentrant.
    1187                 :      */
    1188                 :     RecompileInfo compiledInfo;
    1189                 : 
    1190                 :     /* Table for referencing types of objects keyed to an allocation site. */
    1191                 :     AllocationSiteTable *allocationSiteTable;
    1192                 : 
    1193                 :     /* Tables for determining types of singleton/JSON objects. */
    1194                 : 
    1195                 :     ArrayTypeTable *arrayTypeTable;
    1196                 :     ObjectTypeTable *objectTypeTable;
    1197                 : 
    1198                 :     void fixArrayType(JSContext *cx, JSObject *obj);
    1199                 :     void fixObjectType(JSContext *cx, JSObject *obj);
    1200                 : 
    1201                 :     /* Constraint solving worklist structures. */
    1202                 : 
    1203                 :     /*
    1204                 :      * Worklist of types which need to be propagated to constraints. We use a
    1205                 :      * worklist to avoid blowing the native stack.
    1206                 :      */
    1207                 :     struct PendingWork
    1208                 :     {
    1209                 :         TypeConstraint *constraint;
    1210                 :         TypeSet *source;
    1211                 :         Type type;
    1212                 :     };
    1213                 :     PendingWork *pendingArray;
    1214                 :     unsigned pendingCount;
    1215                 :     unsigned pendingCapacity;
    1216                 : 
    1217                 :     /* Whether we are currently resolving the pending worklist. */
    1218                 :     bool resolving;
    1219                 : 
    1220                 :     /* Logging fields */
    1221                 : 
    1222                 :     /* Counts of stack type sets with some number of possible operand types. */
    1223                 :     static const unsigned TYPE_COUNT_LIMIT = 4;
    1224                 :     unsigned typeCounts[TYPE_COUNT_LIMIT];
    1225                 :     unsigned typeCountOver;
    1226                 : 
    1227                 :     void init(JSContext *cx);
    1228                 :     ~TypeCompartment();
    1229                 : 
    1230                 :     inline JSCompartment *compartment();
    1231                 : 
    1232                 :     /* Add a type to register with a list of constraints. */
    1233                 :     inline void addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type);
    1234                 :     bool growPendingArray(JSContext *cx);
    1235                 : 
    1236                 :     /* Resolve pending type registrations, excluding delayed ones. */
    1237                 :     inline void resolvePending(JSContext *cx);
    1238                 : 
    1239                 :     /* Prints results of this compartment if spew is enabled or force is set. */
    1240                 :     void print(JSContext *cx, bool force);
    1241                 : 
    1242                 :     /*
    1243                 :      * Make a function or non-function object associated with an optional
    1244                 :      * script. The 'key' parameter here may be an array, typed array, function
    1245                 :      * or JSProto_Object to indicate a type whose class is unknown (not just
    1246                 :      * js_ObjectClass).
    1247                 :      */
    1248                 :     TypeObject *newTypeObject(JSContext *cx, JSScript *script,
    1249                 :                               JSProtoKey kind, JSObject *proto, bool unknown = false);
    1250                 : 
    1251                 :     /* Make an object for an allocation site. */
    1252                 :     TypeObject *newAllocationSiteTypeObject(JSContext *cx, const AllocationSiteKey &key);
    1253                 : 
    1254                 :     void nukeTypes(JSContext *cx);
    1255                 :     void processPendingRecompiles(JSContext *cx);
    1256                 : 
    1257                 :     /* Mark all types as needing destruction once inference has 'finished'. */
    1258                 :     void setPendingNukeTypes(JSContext *cx);
    1259                 : 
    1260                 :     /* Mark a script as needing recompilation once inference has finished. */
    1261                 :     void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
    1262                 :     void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
    1263                 : 
    1264                 :     /* Monitor future effects on a bytecode. */
    1265                 :     void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
    1266                 :                          bool returnOnly = false);
    1267                 : 
    1268                 :     /* Mark any type set containing obj as having a generic object type. */
    1269                 :     void markSetsUnknown(JSContext *cx, TypeObject *obj);
    1270                 : 
    1271                 :     void sweep(JSContext *cx);
    1272                 :     void finalizeObjects();
    1273                 : };
    1274                 : 
    1275                 : enum SpewChannel {
    1276                 :     ISpewOps,      /* ops: New constraints and types. */
    1277                 :     ISpewResult,   /* result: Final type sets. */
    1278                 :     SPEW_COUNT
    1279                 : };
    1280                 : 
    1281                 : #ifdef DEBUG
    1282                 : 
    1283                 : const char * InferSpewColorReset();
    1284                 : const char * InferSpewColor(TypeConstraint *constraint);
    1285                 : const char * InferSpewColor(TypeSet *types);
    1286                 : 
    1287                 : void InferSpew(SpewChannel which, const char *fmt, ...);
    1288                 : const char * TypeString(Type type);
    1289                 : const char * TypeObjectString(TypeObject *type);
    1290                 : 
    1291                 : /* Check that the type property for id in obj contains value. */
    1292                 : bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
    1293                 : 
    1294                 : #else
    1295                 : 
    1296                 : inline const char * InferSpewColorReset() { return NULL; }
    1297                 : inline const char * InferSpewColor(TypeConstraint *constraint) { return NULL; }
    1298                 : inline const char * InferSpewColor(TypeSet *types) { return NULL; }
    1299                 : inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
    1300                 : inline const char * TypeString(Type type) { return NULL; }
    1301                 : inline const char * TypeObjectString(TypeObject *type) { return NULL; }
    1302                 : 
    1303                 : #endif
    1304                 : 
    1305                 : /* Print a warning, dump state and abort the program. */
    1306                 : void TypeFailure(JSContext *cx, const char *fmt, ...);
    1307                 : 
    1308                 : } /* namespace types */
    1309                 : } /* namespace js */
    1310                 : 
    1311                 : namespace JS {
    1312                 :     template<> class AnchorPermitted<js::types::TypeObject *> { };
    1313                 : }
    1314                 : 
    1315                 : #endif // jsinfer_h___

Generated by: LCOV version 1.7