LCOV - app.info - js/src/jsinfer.h

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