LCOV - code coverage report
Current view: directory - js/src - jsinferinlines.h (source / functions) Found Hit Coverage
Test: app.info Lines: 639 600 93.9 %
Date: 2012-06-02 Functions: 101 99 98.0 %

       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                 : /* Inline members for javascript type inference. */
      41                 : 
      42                 : #include "jsarray.h"
      43                 : #include "jsanalyze.h"
      44                 : #include "jscompartment.h"
      45                 : #include "jsgcmark.h"
      46                 : #include "jsinfer.h"
      47                 : #include "jsprf.h"
      48                 : #include "vm/GlobalObject.h"
      49                 : 
      50                 : #include "vm/Stack-inl.h"
      51                 : 
      52                 : #ifndef jsinferinlines_h___
      53                 : #define jsinferinlines_h___
      54                 : 
      55                 : /////////////////////////////////////////////////////////////////////
      56                 : // Types
      57                 : /////////////////////////////////////////////////////////////////////
      58                 : 
      59                 : namespace js {
      60                 : namespace types {
      61                 : 
      62                 : /* static */ inline Type
      63        42524920 : Type::ObjectType(JSObject *obj)
      64                 : {
      65        42524920 :     if (obj->hasSingletonType())
      66         9507877 :         return Type(uintptr_t(obj) | 1);
      67        33017043 :     return Type(uintptr_t(obj->type()));
      68                 : }
      69                 : 
      70                 : /* static */ inline Type
      71         1062527 : Type::ObjectType(TypeObject *obj)
      72                 : {
      73         1062527 :     if (obj->singleton)
      74          124092 :         return Type(uintptr_t(obj->singleton.get()) | 1);
      75          938435 :     return Type(uintptr_t(obj));
      76                 : }
      77                 : 
      78                 : /* static */ inline Type
      79          567207 : Type::ObjectType(TypeObjectKey *obj)
      80                 : {
      81          567207 :     return Type(uintptr_t(obj));
      82                 : }
      83                 : 
      84                 : inline Type
      85       168541971 : GetValueType(JSContext *cx, const Value &val)
      86                 : {
      87       168541971 :     JS_ASSERT(cx->typeInferenceEnabled());
      88       168541971 :     if (val.isDouble())
      89        11838191 :         return Type::DoubleType();
      90       156703780 :     if (val.isObject())
      91        41713240 :         return Type::ObjectType(&val.toObject());
      92       114990540 :     return Type::PrimitiveType(val.extractNonDoubleType());
      93                 : }
      94                 : 
      95                 : inline TypeFlags
      96       117997633 : PrimitiveTypeFlag(JSValueType type)
      97                 : {
      98       117997633 :     switch (type) {
      99                 :       case JSVAL_TYPE_UNDEFINED:
     100        11250850 :         return TYPE_FLAG_UNDEFINED;
     101                 :       case JSVAL_TYPE_NULL:
     102         3500577 :         return TYPE_FLAG_NULL;
     103                 :       case JSVAL_TYPE_BOOLEAN:
     104         2194125 :         return TYPE_FLAG_BOOLEAN;
     105                 :       case JSVAL_TYPE_INT32:
     106        80194798 :         return TYPE_FLAG_INT32;
     107                 :       case JSVAL_TYPE_DOUBLE:
     108        12237227 :         return TYPE_FLAG_DOUBLE;
     109                 :       case JSVAL_TYPE_STRING:
     110         8576169 :         return TYPE_FLAG_STRING;
     111                 :       case JSVAL_TYPE_MAGIC:
     112           43887 :         return TYPE_FLAG_LAZYARGS;
     113                 :       default:
     114               0 :         JS_NOT_REACHED("Bad type");
     115                 :         return 0;
     116                 :     }
     117                 : }
     118                 : 
     119                 : inline JSValueType
     120          774277 : TypeFlagPrimitive(TypeFlags flags)
     121                 : {
     122          774277 :     switch (flags) {
     123                 :       case TYPE_FLAG_UNDEFINED:
     124          128342 :         return JSVAL_TYPE_UNDEFINED;
     125                 :       case TYPE_FLAG_NULL:
     126            7374 :         return JSVAL_TYPE_NULL;
     127                 :       case TYPE_FLAG_BOOLEAN:
     128            8913 :         return JSVAL_TYPE_BOOLEAN;
     129                 :       case TYPE_FLAG_INT32:
     130          548025 :         return JSVAL_TYPE_INT32;
     131                 :       case TYPE_FLAG_DOUBLE:
     132           13081 :         return JSVAL_TYPE_DOUBLE;
     133                 :       case TYPE_FLAG_STRING:
     134           66228 :         return JSVAL_TYPE_STRING;
     135                 :       case TYPE_FLAG_LAZYARGS:
     136            2314 :         return JSVAL_TYPE_MAGIC;
     137                 :       default:
     138               0 :         JS_NOT_REACHED("Bad type");
     139                 :         return (JSValueType) 0;
     140                 :     }
     141                 : }
     142                 : 
     143                 : /*
     144                 :  * Get the canonical representation of an id to use when doing inference.  This
     145                 :  * maintains the constraint that if two different jsids map to the same property
     146                 :  * in JS (e.g. 3 and "3"), they have the same type representation.
     147                 :  */
     148                 : inline jsid
     149        73460342 : MakeTypeId(JSContext *cx, jsid id)
     150                 : {
     151        73460342 :     JS_ASSERT(!JSID_IS_EMPTY(id));
     152                 : 
     153                 :     /*
     154                 :      * All integers must map to the aggregate property for index types, including
     155                 :      * negative integers.
     156                 :      */
     157        73460342 :     if (JSID_IS_INT(id))
     158         1471019 :         return JSID_VOID;
     159                 : 
     160                 :     /*
     161                 :      * Check for numeric strings, as in js_StringIsIndex, but allow negative
     162                 :      * and overflowing integers.
     163                 :      */
     164        71989323 :     if (JSID_IS_STRING(id)) {
     165        41388432 :         JSFlatString *str = JSID_TO_FLAT_STRING(id);
     166        41388432 :         const jschar *cp = str->getCharsZ(cx);
     167        41388432 :         if (JS7_ISDEC(*cp) || *cp == '-') {
     168           25257 :             cp++;
     169           56166 :             while (JS7_ISDEC(*cp))
     170            5652 :                 cp++;
     171           25257 :             if (*cp == 0)
     172            2905 :                 return JSID_VOID;
     173                 :         }
     174        41385527 :         return id;
     175                 :     }
     176                 : 
     177        30600891 :     return JSID_VOID;
     178                 : }
     179                 : 
     180                 : const char * TypeIdStringImpl(jsid id);
     181                 : 
     182                 : /* Convert an id for printing during debug. */
     183                 : static inline const char *
     184          188589 : TypeIdString(jsid id)
     185                 : {
     186                 : #ifdef DEBUG
     187          188589 :     return TypeIdStringImpl(id);
     188                 : #else
     189                 :     return "(missing)";
     190                 : #endif
     191                 : }
     192                 : 
     193                 : /*
     194                 :  * Structure for type inference entry point functions. All functions which can
     195                 :  * change type information must use this, and functions which depend on
     196                 :  * intermediate types (i.e. JITs) can use this to ensure that intermediate
     197                 :  * information is not collected and does not change.
     198                 :  *
     199                 :  * Pins inference results so that intermediate type information, TypeObjects
     200                 :  * and JSScripts won't be collected during GC. Does additional sanity checking
     201                 :  * that inference is not reentrant and that recompilations occur properly.
     202                 :  */
     203                 : struct AutoEnterTypeInference
     204                 : {
     205                 :     JSContext *cx;
     206                 :     bool oldActiveAnalysis;
     207                 :     bool oldActiveInference;
     208                 : 
     209       956730921 :     AutoEnterTypeInference(JSContext *cx, bool compiling = false)
     210                 :         : cx(cx), oldActiveAnalysis(cx->compartment->activeAnalysis),
     211       956730921 :           oldActiveInference(cx->compartment->activeInference)
     212                 :     {
     213       956730921 :         JS_ASSERT_IF(!compiling, cx->compartment->types.inferenceEnabled);
     214       956730921 :         cx->compartment->activeAnalysis = true;
     215       956730921 :         cx->compartment->activeInference = true;
     216       956730921 :     }
     217                 : 
     218       956730921 :     ~AutoEnterTypeInference()
     219                 :     {
     220       956730921 :         cx->compartment->activeAnalysis = oldActiveAnalysis;
     221       956730921 :         cx->compartment->activeInference = oldActiveInference;
     222                 : 
     223                 :         /*
     224                 :          * If there are no more type inference activations on the stack,
     225                 :          * process any triggered recompilations. Note that we should not be
     226                 :          * invoking any scripted code while type inference is running.
     227                 :          * :TODO: assert this.
     228                 :          */
     229       956730921 :         if (!cx->compartment->activeInference) {
     230       956570377 :             TypeCompartment *types = &cx->compartment->types;
     231       956570377 :             if (types->pendingNukeTypes)
     232               0 :                 types->nukeTypes(cx);
     233       956570377 :             else if (types->pendingRecompiles)
     234           32646 :                 types->processPendingRecompiles(cx);
     235                 :         }
     236       956730921 :     }
     237                 : };
     238                 : 
     239                 : /*
     240                 :  * Structure marking the currently compiled script, for constraints which can
     241                 :  * trigger recompilation.
     242                 :  */
     243                 : struct AutoEnterCompilation
     244                 : {
     245                 :     RecompileInfo &info;
     246                 : 
     247          134091 :     AutoEnterCompilation(JSContext *cx, JSScript *script, bool constructing, unsigned chunkIndex)
     248          134091 :         : info(cx->compartment->types.compiledInfo)
     249                 :     {
     250          134091 :         JS_ASSERT(!info.script);
     251          134091 :         info.script = script;
     252          134091 :         info.constructing = constructing;
     253          134091 :         info.chunkIndex = chunkIndex;
     254          134091 :     }
     255                 : 
     256          134091 :     ~AutoEnterCompilation()
     257                 :     {
     258          134091 :         JS_ASSERT(info.script);
     259          134091 :         info.script = NULL;
     260          134091 :         info.constructing = false;
     261          134091 :         info.chunkIndex = 0;
     262          134091 :     }
     263                 : };
     264                 : 
     265                 : /////////////////////////////////////////////////////////////////////
     266                 : // Interface functions
     267                 : /////////////////////////////////////////////////////////////////////
     268                 : 
     269                 : /*
     270                 :  * These functions check whether inference is enabled before performing some
     271                 :  * action on the type state. To avoid checking cx->typeInferenceEnabled()
     272                 :  * everywhere, it is generally preferred to use one of these functions or
     273                 :  * a type function on JSScript to perform inference operations.
     274                 :  */
     275                 : 
     276                 : /*
     277                 :  * Get the default 'new' object for a given standard class, per the currently
     278                 :  * active global.
     279                 :  */
     280                 : inline TypeObject *
     281         1632196 : GetTypeNewObject(JSContext *cx, JSProtoKey key)
     282                 : {
     283                 :     JSObject *proto;
     284         1632196 :     if (!js_GetClassPrototype(cx, NULL, key, &proto, NULL))
     285               0 :         return NULL;
     286         1632196 :     return proto->getNewType(cx);
     287                 : }
     288                 : 
     289                 : /* Get a type object for the immediate allocation site within a native. */
     290                 : inline TypeObject *
     291          150081 : GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
     292                 : {
     293          150081 :     if (cx->typeInferenceEnabled()) {
     294                 :         jsbytecode *pc;
     295           53876 :         JSScript *script = cx->stack.currentScript(&pc);
     296           53876 :         if (script)
     297           53751 :             return TypeScript::InitObject(cx, script, pc, key);
     298                 :     }
     299           96330 :     return GetTypeNewObject(cx, key);
     300                 : }
     301                 : 
     302                 : /*
     303                 :  * When using a custom iterator within the initialization of a 'for in' loop,
     304                 :  * mark the iterator values as unknown.
     305                 :  */
     306                 : inline void
     307           11978 : MarkIteratorUnknown(JSContext *cx)
     308                 : {
     309                 :     extern void MarkIteratorUnknownSlow(JSContext *cx);
     310                 : 
     311           11978 :     if (cx->typeInferenceEnabled())
     312            2377 :         MarkIteratorUnknownSlow(cx);
     313           11978 : }
     314                 : 
     315                 : /*
     316                 :  * Monitor a javascript call, either on entry to the interpreter or made
     317                 :  * from within the interpreter.
     318                 :  */
     319                 : inline void
     320        28978716 : TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
     321                 : {
     322                 :     extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
     323                 :                                     const CallArgs &args, bool constructing);
     324                 : 
     325        28978716 :     JSObject *callee = &args.callee();
     326        28978716 :     if (callee->isFunction()) {
     327        28978716 :         JSFunction *fun = callee->toFunction();
     328        28978716 :         if (fun->isInterpreted()) {
     329        28978716 :             JSScript *script = fun->script();
     330        28978716 :             if (!script->ensureRanAnalysis(cx, fun->environment()))
     331               0 :                 return;
     332        28978716 :             if (cx->typeInferenceEnabled())
     333        12954220 :                 TypeMonitorCallSlow(cx, callee, args, constructing);
     334                 :         }
     335                 :     }
     336                 : }
     337                 : 
     338                 : inline bool
     339       133351572 : TrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
     340                 : {
     341       133351572 :     if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
     342       112740486 :         return false;
     343                 : 
     344        20611086 :     if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id))
     345         6964699 :         return false;
     346                 : 
     347        13646387 :     return true;
     348                 : }
     349                 : 
     350                 : /* Add a possible type for a property of obj. */
     351                 : inline void
     352         2702277 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, Type type)
     353                 : {
     354         2702277 :     if (cx->typeInferenceEnabled())
     355          679899 :         id = MakeTypeId(cx, id);
     356         2702277 :     if (TrackPropertyTypes(cx, obj, id))
     357          272835 :         obj->type()->addPropertyType(cx, id, type);
     358         2702277 : }
     359                 : 
     360                 : inline void
     361       114876970 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, const Value &value)
     362                 : {
     363       114876970 :     if (cx->typeInferenceEnabled())
     364        27821924 :         id = MakeTypeId(cx, id);
     365       114876970 :     if (TrackPropertyTypes(cx, obj, id))
     366        13097911 :         obj->type()->addPropertyType(cx, id, value);
     367       114876970 : }
     368                 : 
     369                 : inline void
     370           98623 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
     371                 : {
     372           98623 :     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
     373           17714 :         obj->addPropertyType(cx, name, type);
     374           98623 : }
     375                 : 
     376                 : inline void
     377               0 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value)
     378                 : {
     379               0 :     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
     380               0 :         obj->addPropertyType(cx, name, value);
     381               0 : }
     382                 : 
     383                 : /* Set one or more dynamic flags on a type object. */
     384                 : inline void
     385        11057790 : MarkTypeObjectFlags(JSContext *cx, JSObject *obj, TypeObjectFlags flags)
     386                 : {
     387        11057790 :     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
     388            6720 :         obj->type()->setFlags(cx, flags);
     389        11057790 : }
     390                 : 
     391                 : /*
     392                 :  * Mark all properties of a type object as unknown. If markSetsUnknown is set,
     393                 :  * scan the entire compartment and mark all type sets containing it as having
     394                 :  * an unknown object. This is needed for correctness in dealing with mutable
     395                 :  * __proto__, which can change the type of an object dynamically.
     396                 :  */
     397                 : inline void
     398         6631537 : MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
     399                 :                                 bool markSetsUnknown = false)
     400                 : {
     401         6631537 :     if (cx->typeInferenceEnabled()) {
     402         2242382 :         if (!obj->unknownProperties())
     403           13465 :             obj->markUnknown(cx);
     404         2242382 :         if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
     405             165 :             cx->compartment->types.markSetsUnknown(cx, obj);
     406                 :     }
     407         6631537 : }
     408                 : 
     409                 : /*
     410                 :  * Mark any property which has been deleted or configured to be non-writable or
     411                 :  * have a getter/setter.
     412                 :  */
     413                 : inline void
     414        15772325 : MarkTypePropertyConfigured(JSContext *cx, JSObject *obj, jsid id)
     415                 : {
     416        15772325 :     if (cx->typeInferenceEnabled())
     417         6794159 :         id = MakeTypeId(cx, id);
     418        15772325 :     if (TrackPropertyTypes(cx, obj, id))
     419          275641 :         obj->type()->markPropertyConfigured(cx, id);
     420        15772325 : }
     421                 : 
     422                 : /* Mark a state change on a particular object. */
     423                 : inline void
     424           38570 : MarkObjectStateChange(JSContext *cx, JSObject *obj)
     425                 : {
     426           38570 :     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
     427           12778 :         obj->type()->markStateChange(cx);
     428           38570 : }
     429                 : 
     430                 : /*
     431                 :  * For an array or object which has not yet escaped and been referenced elsewhere,
     432                 :  * pick a new type based on the object's current contents.
     433                 :  */
     434                 : 
     435                 : inline void
     436            5767 : FixArrayType(JSContext *cx, JSObject *obj)
     437                 : {
     438            5767 :     if (cx->typeInferenceEnabled())
     439            1775 :         cx->compartment->types.fixArrayType(cx, obj);
     440            5767 : }
     441                 : 
     442                 : inline void
     443            2413 : FixObjectType(JSContext *cx, JSObject *obj)
     444                 : {
     445            2413 :     if (cx->typeInferenceEnabled())
     446            1323 :         cx->compartment->types.fixObjectType(cx, obj);
     447            2413 : }
     448                 : 
     449                 : /* Interface helpers for JSScript */
     450                 : extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
     451                 : extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
     452                 : 
     453                 : inline bool
     454         1962019 : UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
     455                 : {
     456         1968496 :     return fp->isConstructing() && cx->typeInferenceEnabled() &&
     457             346 :            fp->prev() && fp->prev()->isScriptFrame() &&
     458         1968842 :            UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
     459                 : }
     460                 : 
     461                 : /////////////////////////////////////////////////////////////////////
     462                 : // Script interface functions
     463                 : /////////////////////////////////////////////////////////////////////
     464                 : 
     465                 : inline
     466          470919 : TypeScript::TypeScript()
     467                 : {
     468          470919 :     this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
     469          470919 : }
     470                 : 
     471                 : /* static */ inline unsigned
     472          199428 : TypeScript::NumTypeSets(JSScript *script)
     473                 : {
     474          199428 :     return script->nTypeSets + analyze::TotalSlots(script);
     475                 : }
     476                 : 
     477                 : /* static */ inline TypeSet *
     478          131434 : TypeScript::ReturnTypes(JSScript *script)
     479                 : {
     480          131434 :     return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
     481                 : }
     482                 : 
     483                 : /* static */ inline TypeSet *
     484        29306782 : TypeScript::ThisTypes(JSScript *script)
     485                 : {
     486        29306782 :     return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
     487                 : }
     488                 : 
     489                 : /*
     490                 :  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
     491                 :  * only the initial type of the variable (e.g. passed values for argTypes,
     492                 :  * or undefined for localTypes) and not types from subsequent assignments.
     493                 :  */
     494                 : 
     495                 : /* static */ inline TypeSet *
     496        45054078 : TypeScript::ArgTypes(JSScript *script, unsigned i)
     497                 : {
     498        45054078 :     JS_ASSERT(i < script->function()->nargs);
     499        45054078 :     return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
     500                 : }
     501                 : 
     502                 : /* static */ inline TypeSet *
     503          109519 : TypeScript::LocalTypes(JSScript *script, unsigned i)
     504                 : {
     505          109519 :     JS_ASSERT(i < script->nfixed);
     506          109519 :     return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
     507                 : }
     508                 : 
     509                 : /* static */ inline TypeSet *
     510          337175 : TypeScript::SlotTypes(JSScript *script, unsigned slot)
     511                 : {
     512          337175 :     JS_ASSERT(slot < js::analyze::TotalSlots(script));
     513          337175 :     return script->types->typeArray() + script->nTypeSets + slot;
     514                 : }
     515                 : 
     516                 : /* static */ inline TypeObject *
     517            8027 : TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
     518                 : {
     519                 :     JSObject *proto;
     520            8027 :     if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
     521               0 :         return NULL;
     522            8027 :     return proto->getNewType(cx);
     523                 : }
     524                 : 
     525                 : struct AllocationSiteKey {
     526                 :     JSScript *script;
     527                 : 
     528                 :     uint32_t offset : 24;
     529                 :     JSProtoKey kind : 8;
     530                 : 
     531                 :     static const uint32_t OFFSET_LIMIT = (1 << 23);
     532                 : 
     533         1282302 :     AllocationSiteKey() { PodZero(this); }
     534                 : 
     535                 :     typedef AllocationSiteKey Lookup;
     536                 : 
     537         1021482 :     static inline uint32_t hash(AllocationSiteKey key) {
     538         1021482 :         return uint32_t(size_t(key.script->code + key.offset)) ^ key.kind;
     539                 :     }
     540                 : 
     541          997436 :     static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
     542          997436 :         return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
     543                 :     }
     544                 : };
     545                 : 
     546                 : /* static */ inline TypeObject *
     547         2547824 : TypeScript::InitObject(JSContext *cx, JSScript *script, const jsbytecode *pc, JSProtoKey kind)
     548                 : {
     549                 :     /* :XXX: Limit script->length so we don't need to check the offset up front? */
     550         2547824 :     uint32_t offset = pc - script->code;
     551                 : 
     552         2547824 :     if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
     553         1535866 :         return GetTypeNewObject(cx, kind);
     554                 : 
     555         1011958 :     AllocationSiteKey key;
     556         1011958 :     key.script = script;
     557         1011958 :     key.offset = offset;
     558         1011958 :     key.kind = kind;
     559                 : 
     560         1011958 :     if (!cx->compartment->types.allocationSiteTable)
     561            5008 :         return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
     562                 : 
     563         1006950 :     AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(key);
     564                 : 
     565         1006950 :     if (p)
     566          997426 :         return p->value;
     567            9524 :     return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
     568                 : }
     569                 : 
     570                 : /* static */ inline void
     571       207366048 : TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
     572                 : {
     573       207366048 :     if (cx->typeInferenceEnabled())
     574        76761967 :         TypeMonitorResult(cx, script, pc, rval);
     575       207366048 : }
     576                 : 
     577                 : /* static */ inline void
     578         1400830 : TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
     579                 : {
     580         1400830 :     if (cx->typeInferenceEnabled())
     581          530616 :         TypeDynamicResult(cx, script, pc, Type::DoubleType());
     582         1400830 : }
     583                 : 
     584                 : /* static */ inline void
     585          544207 : TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
     586                 : {
     587          544207 :     if (cx->typeInferenceEnabled())
     588          282970 :         TypeDynamicResult(cx, script, pc, Type::StringType());
     589          544207 : }
     590                 : 
     591                 : /* static */ inline void
     592            3237 : TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
     593                 : {
     594            3237 :     if (cx->typeInferenceEnabled())
     595            1570 :         TypeDynamicResult(cx, script, pc, Type::UnknownType());
     596            3237 : }
     597                 : 
     598                 : /* static */ inline void
     599         5122251 : TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
     600                 : {
     601         5122251 :     *script = cx->fp()->script();
     602         5122251 :     *pc = cx->regs().pc;
     603         5122251 : }
     604                 : 
     605                 : /* static */ inline void
     606         1001716 : TypeScript::MonitorOverflow(JSContext *cx)
     607                 : {
     608                 :     JSScript *script;
     609                 :     jsbytecode *pc;
     610         1001716 :     GetPcScript(cx, &script, &pc);
     611         1001716 :     MonitorOverflow(cx, script, pc);
     612         1001716 : }
     613                 : 
     614                 : /* static */ inline void
     615          149802 : TypeScript::MonitorString(JSContext *cx)
     616                 : {
     617                 :     JSScript *script;
     618                 :     jsbytecode *pc;
     619          149802 :     GetPcScript(cx, &script, &pc);
     620          149802 :     MonitorString(cx, script, pc);
     621          149802 : }
     622                 : 
     623                 : /* static */ inline void
     624             884 : TypeScript::MonitorUnknown(JSContext *cx)
     625                 : {
     626                 :     JSScript *script;
     627                 :     jsbytecode *pc;
     628             884 :     GetPcScript(cx, &script, &pc);
     629             884 :     MonitorUnknown(cx, script, pc);
     630             884 : }
     631                 : 
     632                 : /* static */ inline void
     633                 : TypeScript::Monitor(JSContext *cx, const js::Value &rval)
     634                 : {
     635                 :     JSScript *script;
     636                 :     jsbytecode *pc;
     637                 :     GetPcScript(cx, &script, &pc);
     638                 :     Monitor(cx, script, pc, rval);
     639                 : }
     640                 : 
     641                 : /* static */ inline void
     642        28933522 : TypeScript::MonitorAssign(JSContext *cx, JSObject *obj, jsid id)
     643                 : {
     644        28933522 :     if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
     645                 :         /*
     646                 :          * Mark as unknown any object which has had dynamic assignments to
     647                 :          * non-integer properties at SETELEM opcodes. This avoids making large
     648                 :          * numbers of type properties for hashmap-style objects. We don't need
     649                 :          * to do this for objects with singleton type, because type properties
     650                 :          * are only constructed for them when analyzed scripts depend on those
     651                 :          * specific properties.
     652                 :          */
     653                 :         uint32_t i;
     654         6091035 :         if (js_IdIsIndex(id, &i))
     655         5688149 :             return;
     656          402886 :         MarkTypeObjectUnknownProperties(cx, obj->type());
     657                 :     }
     658                 : }
     659                 : 
     660                 : /* static */ inline void
     661        12507347 : TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
     662                 : {
     663        12507347 :     if (!cx->typeInferenceEnabled())
     664               0 :         return;
     665        12507347 :     JS_ASSERT(script->types);
     666                 : 
     667                 :     /* Analyze the script regardless if -a was used. */
     668        12507347 :     bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS);
     669                 : 
     670        12507347 :     if (!ThisTypes(script)->hasType(type) || analyze) {
     671         8513014 :         AutoEnterTypeInference enter(cx);
     672                 : 
     673                 :         InferSpew(ISpewOps, "externalType: setThis #%u: %s",
     674         4256507 :                   script->id(), TypeString(type));
     675         4256507 :         ThisTypes(script)->addType(cx, type);
     676                 : 
     677         4256507 :         if (analyze && script->types->hasScope())
     678         4206469 :             script->ensureRanInference(cx);
     679                 :     }
     680                 : }
     681                 : 
     682                 : /* static */ inline void
     683        11821918 : TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
     684                 : {
     685        11821918 :     if (cx->typeInferenceEnabled())
     686        11726715 :         SetThis(cx, script, GetValueType(cx, value));
     687        11821918 : }
     688                 : 
     689                 : /* static */ inline void
     690           10729 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
     691                 : {
     692           10729 :     if (!cx->typeInferenceEnabled())
     693               0 :         return;
     694           10729 :     JS_ASSERT(script->types);
     695                 : 
     696           10729 :     if (!LocalTypes(script, local)->hasType(type)) {
     697             900 :         AutoEnterTypeInference enter(cx);
     698                 : 
     699                 :         InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
     700             450 :                   script->id(), local, TypeString(type));
     701             450 :         LocalTypes(script, local)->addType(cx, type);
     702                 :     }
     703                 : }
     704                 : 
     705                 : /* static */ inline void
     706           37339 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
     707                 : {
     708           37339 :     if (cx->typeInferenceEnabled()) {
     709           10729 :         Type type = GetValueType(cx, value);
     710           10729 :         SetLocal(cx, script, local, type);
     711                 :     }
     712           37339 : }
     713                 : 
     714                 : /* static */ inline void
     715        20682835 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
     716                 : {
     717        20682835 :     if (!cx->typeInferenceEnabled())
     718               0 :         return;
     719        20682835 :     JS_ASSERT(script->types);
     720                 : 
     721        20682835 :     if (!ArgTypes(script, arg)->hasType(type)) {
     722          166014 :         AutoEnterTypeInference enter(cx);
     723                 : 
     724                 :         InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
     725           83007 :                   script->id(), arg, TypeString(type));
     726           83007 :         ArgTypes(script, arg)->addType(cx, type);
     727                 :     }
     728                 : }
     729                 : 
     730                 : /* static */ inline void
     731        20685872 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
     732                 : {
     733        20685872 :     if (cx->typeInferenceEnabled()) {
     734        20682835 :         Type type = GetValueType(cx, value);
     735        20682835 :         SetArgument(cx, script, arg, type);
     736                 :     }
     737        20685872 : }
     738                 : 
     739                 : void
     740         1954054 : TypeScript::trace(JSTracer *trc)
     741                 : {
     742         1954054 :     if (hasScope() && global)
     743           66908 :         gc::MarkObject(trc, &global, "script_global");
     744                 : 
     745                 :     /* Note: nesting does not keep anything alive. */
     746         1954054 : }
     747                 : 
     748                 : /////////////////////////////////////////////////////////////////////
     749                 : // TypeCompartment
     750                 : /////////////////////////////////////////////////////////////////////
     751                 : 
     752                 : inline JSCompartment *
     753          164383 : TypeCompartment::compartment()
     754                 : {
     755          164383 :     return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
     756                 : }
     757                 : 
     758                 : inline void
     759         3123940 : TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type)
     760                 : {
     761         3123940 :     JS_ASSERT(this == &cx->compartment->types);
     762         3123940 :     JS_ASSERT(!cx->runtime->gcRunning);
     763                 : 
     764                 :     InferSpew(ISpewOps, "pending: %sC%p%s %s",
     765                 :               InferSpewColor(constraint), constraint, InferSpewColorReset(),
     766         3123940 :               TypeString(type));
     767                 : 
     768         3123940 :     if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
     769               0 :         return;
     770                 : 
     771         3123940 :     PendingWork &pending = pendingArray[pendingCount++];
     772         3123940 :     pending.constraint = constraint;
     773         3123940 :     pending.source = source;
     774         3123940 :     pending.type = type;
     775                 : }
     776                 : 
     777                 : inline void
     778         4588579 : TypeCompartment::resolvePending(JSContext *cx)
     779                 : {
     780         4588579 :     JS_ASSERT(this == &cx->compartment->types);
     781                 : 
     782         4588579 :     if (resolving) {
     783                 :         /* There is an active call further up resolving the worklist. */
     784         1193329 :         return;
     785                 :     }
     786                 : 
     787         3395250 :     resolving = true;
     788                 : 
     789                 :     /* Handle all pending type registrations. */
     790         9914440 :     while (pendingCount) {
     791         3123940 :         const PendingWork &pending = pendingArray[--pendingCount];
     792                 :         InferSpew(ISpewOps, "resolve: %sC%p%s %s",
     793                 :                   InferSpewColor(pending.constraint), pending.constraint,
     794         3123940 :                   InferSpewColorReset(), TypeString(pending.type));
     795         3123940 :         pending.constraint->newType(cx, pending.source, pending.type);
     796                 :     }
     797                 : 
     798         3395250 :     resolving = false;
     799                 : }
     800                 : 
     801                 : /////////////////////////////////////////////////////////////////////
     802                 : // TypeSet
     803                 : /////////////////////////////////////////////////////////////////////
     804                 : 
     805                 : /*
     806                 :  * The sets of objects and scripts in a type set grow monotonically, are usually
     807                 :  * empty, almost always small, and sometimes big.  For empty or singleton sets,
     808                 :  * the pointer refers directly to the value.  For sets fitting into SET_ARRAY_SIZE,
     809                 :  * an array of this length is used to store the elements.  For larger sets, a hash
     810                 :  * table filled to 25%-50% of capacity is used, with collisions resolved by linear
     811                 :  * probing.  TODO: replace these with jshashtables.
     812                 :  */
     813                 : const unsigned SET_ARRAY_SIZE = 8;
     814                 : 
     815                 : /* Get the capacity of a set with the given element count. */
     816                 : static inline unsigned
     817         4294124 : HashSetCapacity(unsigned count)
     818                 : {
     819         4294124 :     JS_ASSERT(count >= 2);
     820                 : 
     821         4294124 :     if (count <= SET_ARRAY_SIZE)
     822           17220 :         return SET_ARRAY_SIZE;
     823                 : 
     824                 :     unsigned log2;
     825         4276904 :     JS_FLOOR_LOG2(log2, count);
     826         4276904 :     return 1 << (log2 + 2);
     827                 : }
     828                 : 
     829                 : /* Compute the FNV hash for the low 32 bits of v. */
     830                 : template <class T, class KEY>
     831                 : static inline uint32_t
     832         2623479 : HashKey(T v)
     833                 : {
     834         2623479 :     uint32_t nv = KEY::keyBits(v);
     835                 : 
     836         2623479 :     uint32_t hash = 84696351 ^ (nv & 0xff);
     837         2623479 :     hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
     838         2623479 :     hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
     839         2623479 :     return (hash * 16777619) ^ ((nv >> 24) & 0xff);
     840                 : }
     841                 : 
     842                 : /*
     843                 :  * Insert space for an element into the specified set and grow its capacity if needed.
     844                 :  * returned value is an existing or new entry (NULL if new).
     845                 :  */
     846                 : template <class T, class U, class KEY>
     847                 : static U **
     848          853802 : HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
     849                 : {
     850          853802 :     unsigned capacity = HashSetCapacity(count);
     851          853802 :     unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
     852                 : 
     853                 :     /* Whether we are converting from a fixed array to hashtable. */
     854          853802 :     bool converting = (count == SET_ARRAY_SIZE);
     855                 : 
     856          853802 :     if (!converting) {
     857         2256352 :         while (values[insertpos] != NULL) {
     858          907782 :             if (KEY::getKey(values[insertpos]) == key)
     859          340016 :                 return &values[insertpos];
     860          567766 :             insertpos = (insertpos + 1) & (capacity - 1);
     861                 :         }
     862                 :     }
     863                 : 
     864          513786 :     count++;
     865          513786 :     unsigned newCapacity = HashSetCapacity(count);
     866                 : 
     867          513786 :     if (newCapacity == capacity) {
     868          488274 :         JS_ASSERT(!converting);
     869          488274 :         return &values[insertpos];
     870                 :     }
     871                 : 
     872           25512 :     U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
     873           25512 :     if (!newValues)
     874               0 :         return NULL;
     875           25512 :     PodZero(newValues, newCapacity);
     876                 : 
     877         1523600 :     for (unsigned i = 0; i < capacity; i++) {
     878         1498088 :         if (values[i]) {
     879          771077 :             unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
     880         1674095 :             while (newValues[pos] != NULL)
     881          131941 :                 pos = (pos + 1) & (newCapacity - 1);
     882          771077 :             newValues[pos] = values[i];
     883                 :         }
     884                 :     }
     885                 : 
     886           25512 :     values = newValues;
     887                 : 
     888           25512 :     insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
     889           63597 :     while (values[insertpos] != NULL)
     890           12573 :         insertpos = (insertpos + 1) & (newCapacity - 1);
     891           25512 :     return &values[insertpos];
     892                 : }
     893                 : 
     894                 : /*
     895                 :  * Insert an element into the specified set if it is not already there, returning
     896                 :  * an entry which is NULL if the element was not there.
     897                 :  */
     898                 : template <class T, class U, class KEY>
     899                 : static inline U **
     900        16983250 : HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
     901                 : {
     902        16983250 :     if (count == 0) {
     903          656712 :         JS_ASSERT(values == NULL);
     904          656712 :         count++;
     905          656712 :         return (U **) &values;
     906                 :     }
     907                 : 
     908        16326538 :     if (count == 1) {
     909        10990045 :         U *oldData = (U*) values;
     910        10990045 :         if (KEY::getKey(oldData) == key)
     911        10934266 :             return (U **) &values;
     912                 : 
     913           55779 :         values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
     914           55779 :         if (!values) {
     915               0 :             values = (U **) oldData;
     916               0 :             return NULL;
     917                 :         }
     918           55779 :         PodZero(values, SET_ARRAY_SIZE);
     919           55779 :         count++;
     920                 : 
     921           55779 :         values[0] = oldData;
     922           55779 :         return &values[1];
     923                 :     }
     924                 : 
     925         5336493 :     if (count <= SET_ARRAY_SIZE) {
     926        12591666 :         for (unsigned i = 0; i < count; i++) {
     927        12473378 :             if (KEY::getKey(values[i]) == key)
     928         4373912 :                 return &values[i];
     929                 :         }
     930                 : 
     931          118288 :         if (count < SET_ARRAY_SIZE) {
     932          108779 :             count++;
     933          108779 :             return &values[count - 1];
     934                 :         }
     935                 :     }
     936                 : 
     937          853802 :     return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
     938                 : }
     939                 : 
     940                 : /* Lookup an entry in a hash set, return NULL if it does not exist. */
     941                 : template <class T, class U, class KEY>
     942                 : static inline U *
     943        49749557 : HashSetLookup(U **values, unsigned count, T key)
     944                 : {
     945        49749557 :     if (count == 0)
     946         7543821 :         return NULL;
     947                 : 
     948        42205736 :     if (count == 1)
     949        34202415 :         return (KEY::getKey((U *) values) == key) ? (U *) values : NULL;
     950                 : 
     951         8003321 :     if (count <= SET_ARRAY_SIZE) {
     952        13154135 :         for (unsigned i = 0; i < count; i++) {
     953        12905984 :             if (KEY::getKey(values[i]) == key)
     954         6782082 :                 return values[i];
     955                 :         }
     956          248151 :         return NULL;
     957                 :     }
     958                 : 
     959          973088 :     unsigned capacity = HashSetCapacity(count);
     960          973088 :     unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
     961                 : 
     962         2726787 :     while (values[pos] != NULL) {
     963         1718084 :         if (KEY::getKey(values[pos]) == key)
     964          937473 :             return values[pos];
     965          780611 :         pos = (pos + 1) & (capacity - 1);
     966                 :     }
     967                 : 
     968           35615 :     return NULL;
     969                 : }
     970                 : 
     971                 : inline bool
     972       172540095 : TypeSet::hasType(Type type)
     973                 : {
     974       172540095 :     if (unknown())
     975        13692890 :         return true;
     976                 : 
     977       158847205 :     if (type.isUnknown()) {
     978           54924 :         return false;
     979       158792281 :     } else if (type.isPrimitive()) {
     980       116203354 :         return !!(flags & PrimitiveTypeFlag(type.primitive()));
     981        42588927 :     } else if (type.isAnyObject()) {
     982          346808 :         return !!(flags & TYPE_FLAG_ANYOBJECT);
     983                 :     } else {
     984        42242119 :         return !!(flags & TYPE_FLAG_ANYOBJECT) ||
     985                 :             HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
     986        42242119 :             (objectSet, baseObjectCount(), type.objectKey()) != NULL;
     987                 :     }
     988                 : }
     989                 : 
     990                 : inline void
     991         1287773 : TypeSet::setBaseObjectCount(uint32_t count)
     992                 : {
     993         1287773 :     JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
     994                 :     flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
     995         1287773 :           | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
     996         1287773 : }
     997                 : 
     998                 : inline void
     999          136081 : TypeSet::clearObjects()
    1000                 : {
    1001          136081 :     setBaseObjectCount(0);
    1002          136081 :     objectSet = NULL;
    1003          136081 : }
    1004                 : 
    1005                 : inline void
    1006         6335990 : TypeSet::addType(JSContext *cx, Type type)
    1007                 : {
    1008         6335990 :     JS_ASSERT(cx->compartment->activeInference);
    1009                 : 
    1010         6335990 :     if (unknown())
    1011         2514138 :         return;
    1012                 : 
    1013         3821852 :     if (type.isUnknown()) {
    1014           72463 :         flags |= TYPE_FLAG_BASE_MASK;
    1015           72463 :         clearObjects();
    1016           72463 :         JS_ASSERT(unknown());
    1017         3749389 :     } else if (type.isPrimitive()) {
    1018         1794279 :         TypeFlags flag = PrimitiveTypeFlag(type.primitive());
    1019         1794279 :         if (flags & flag)
    1020          764526 :             return;
    1021                 : 
    1022                 :         /* If we add float to a type set it is also considered to contain int. */
    1023         1029753 :         if (flag == TYPE_FLAG_DOUBLE)
    1024           49054 :             flag |= TYPE_FLAG_INT32;
    1025                 : 
    1026         1029753 :         flags |= flag;
    1027                 :     } else {
    1028         1955110 :         if (flags & TYPE_FLAG_ANYOBJECT)
    1029            5108 :             return;
    1030         1950002 :         if (type.isAnyObject())
    1031           26439 :             goto unknownObject;
    1032         1923563 :         uint32_t objectCount = baseObjectCount();
    1033         1923563 :         TypeObjectKey *object = type.objectKey();
    1034                 :         TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
    1035         1923563 :                                      (cx->compartment, objectSet, objectCount, object);
    1036         1923563 :         if (!pentry) {
    1037               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    1038               0 :             return;
    1039                 :         }
    1040         1923563 :         if (*pentry)
    1041         1042561 :             return;
    1042          881002 :         *pentry = object;
    1043                 : 
    1044          881002 :         setBaseObjectCount(objectCount);
    1045                 : 
    1046          881002 :         if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
    1047              15 :             goto unknownObject;
    1048                 : 
    1049          880987 :         if (type.isTypeObject()) {
    1050          291534 :             TypeObject *nobject = type.typeObject();
    1051          291534 :             JS_ASSERT(!nobject->singleton);
    1052          291534 :             if (nobject->unknownProperties())
    1053           26648 :                 goto unknownObject;
    1054          264886 :             if (objectCount > 1) {
    1055           34299 :                 nobject->contribution += (objectCount - 1) * (objectCount - 1);
    1056           34299 :                 if (nobject->contribution >= TypeObject::CONTRIBUTION_LIMIT) {
    1057                 :                     InferSpew(ISpewOps, "limitUnknown: %sT%p%s",
    1058             392 :                               InferSpewColor(this), this, InferSpewColorReset());
    1059             392 :                     goto unknownObject;
    1060                 :                 }
    1061                 :             }
    1062                 :         }
    1063                 :     }
    1064                 : 
    1065                 :     if (false) {
    1066                 :     unknownObject:
    1067           53494 :         type = Type::AnyObjectType();
    1068           53494 :         flags |= TYPE_FLAG_ANYOBJECT;
    1069           53494 :         clearObjects();
    1070                 :     }
    1071                 : 
    1072                 :     InferSpew(ISpewOps, "addType: %sT%p%s %s",
    1073                 :               InferSpewColor(this), this, InferSpewColorReset(),
    1074         2009657 :               TypeString(type));
    1075                 : 
    1076                 :     /* Propagate the type to all constraints. */
    1077         2009657 :     TypeConstraint *constraint = constraintList;
    1078         5767538 :     while (constraint) {
    1079         1748224 :         cx->compartment->types.addPending(cx, constraint, this, type);
    1080         1748224 :         constraint = constraint->next;
    1081                 :     }
    1082                 : 
    1083         2009657 :     cx->compartment->types.resolvePending(cx);
    1084                 : }
    1085                 : 
    1086                 : inline void
    1087        14064721 : TypeSet::setOwnProperty(JSContext *cx, bool configured)
    1088                 : {
    1089        14064721 :     TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0);
    1090                 : 
    1091        14064721 :     if ((flags & nflags) == nflags)
    1092        13981930 :         return;
    1093                 : 
    1094           82791 :     flags |= nflags;
    1095                 : 
    1096                 :     /* Propagate the change to all constraints. */
    1097           82791 :     TypeConstraint *constraint = constraintList;
    1098          172484 :     while (constraint) {
    1099            6902 :         constraint->newPropertyState(cx, this);
    1100            6902 :         constraint = constraint->next;
    1101                 :     }
    1102                 : }
    1103                 : 
    1104                 : inline unsigned
    1105         6390705 : TypeSet::getObjectCount()
    1106                 : {
    1107         6390705 :     JS_ASSERT(!unknownObject());
    1108         6390705 :     uint32_t count = baseObjectCount();
    1109         6390705 :     if (count > SET_ARRAY_SIZE)
    1110         1940082 :         return HashSetCapacity(count);
    1111         4450623 :     return count;
    1112                 : }
    1113                 : 
    1114                 : inline TypeObjectKey *
    1115         2621547 : TypeSet::getObject(unsigned i)
    1116                 : {
    1117         2621547 :     JS_ASSERT(i < getObjectCount());
    1118         2621547 :     if (baseObjectCount() == 1) {
    1119          843625 :         JS_ASSERT(i == 0);
    1120          843625 :         return (TypeObjectKey *) objectSet;
    1121                 :     }
    1122         1777922 :     return objectSet[i];
    1123                 : }
    1124                 : 
    1125                 : inline JSObject *
    1126          760618 : TypeSet::getSingleObject(unsigned i)
    1127                 : {
    1128          760618 :     TypeObjectKey *key = getObject(i);
    1129          760618 :     return (uintptr_t(key) & 1) ? (JSObject *)(uintptr_t(key) ^ 1) : NULL;
    1130                 : }
    1131                 : 
    1132                 : inline TypeObject *
    1133          840785 : TypeSet::getTypeObject(unsigned i)
    1134                 : {
    1135          840785 :     TypeObjectKey *key = getObject(i);
    1136          840785 :     return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;
    1137                 : }
    1138                 : 
    1139                 : /////////////////////////////////////////////////////////////////////
    1140                 : // TypeCallsite
    1141                 : /////////////////////////////////////////////////////////////////////
    1142                 : 
    1143                 : inline
    1144           56863 : TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
    1145                 :                            bool isNew, unsigned argumentCount)
    1146                 :     : script(script), pc(pc), isNew(isNew), argumentCount(argumentCount),
    1147           56863 :       thisTypes(NULL), returnTypes(NULL)
    1148                 : {
    1149                 :     /* Caller must check for failure. */
    1150           56863 :     argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
    1151           56863 : }
    1152                 : 
    1153                 : /////////////////////////////////////////////////////////////////////
    1154                 : // TypeObject
    1155                 : /////////////////////////////////////////////////////////////////////
    1156                 : 
    1157          671141 : inline TypeObject::TypeObject(JSObject *proto, bool function, bool unknown)
    1158                 : {
    1159          671141 :     PodZero(this);
    1160                 : 
    1161                 :     /* Inner objects may not appear on prototype chains. */
    1162          671141 :     JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
    1163                 : 
    1164          671141 :     this->proto = proto;
    1165                 : 
    1166          671141 :     if (function)
    1167           13763 :         flags |= OBJECT_FLAG_FUNCTION;
    1168          671141 :     if (unknown)
    1169          444465 :         flags |= OBJECT_FLAG_UNKNOWN_MASK;
    1170                 : 
    1171          671141 :     InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
    1172          671141 : }
    1173                 : 
    1174                 : inline uint32_t
    1175        31643695 : TypeObject::basePropertyCount() const
    1176                 : {
    1177        31643695 :     return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
    1178                 : }
    1179                 : 
    1180                 : inline void
    1181          342694 : TypeObject::setBasePropertyCount(uint32_t count)
    1182                 : {
    1183          342694 :     JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
    1184                 :     flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
    1185          342694 :           | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
    1186          342694 : }
    1187                 : 
    1188                 : inline TypeSet *
    1189        14751310 : TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
    1190                 : {
    1191        14751310 :     JS_ASSERT(cx->compartment->activeInference);
    1192        14751310 :     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
    1193        14751310 :     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
    1194        14751310 :     JS_ASSERT(!unknownProperties());
    1195                 : 
    1196        14751310 :     uint32_t propertyCount = basePropertyCount();
    1197                 :     Property **pprop = HashSetInsert<jsid,Property,Property>
    1198        14751310 :                            (cx->compartment, propertySet, propertyCount, id);
    1199        14751310 :     if (!pprop) {
    1200               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    1201               0 :         return NULL;
    1202                 :     }
    1203                 : 
    1204        14751310 :     if (!*pprop) {
    1205          145677 :         setBasePropertyCount(propertyCount);
    1206          145677 :         if (!addProperty(cx, id, pprop))
    1207               0 :             return NULL;
    1208          145677 :         if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
    1209               0 :             markUnknown(cx);
    1210               0 :             TypeSet *types = TypeSet::make(cx, "propertyOverflow");
    1211               0 :             types->addType(cx, Type::UnknownType());
    1212               0 :             return types;
    1213                 :         }
    1214                 :     }
    1215                 : 
    1216        14751310 :     TypeSet *types = &(*pprop)->types;
    1217                 : 
    1218        14751310 :     if (assign)
    1219        13741533 :         types->setOwnProperty(cx, false);
    1220                 : 
    1221        14751310 :     return types;
    1222                 : }
    1223                 : 
    1224                 : inline TypeSet *
    1225         8428130 : TypeObject::maybeGetProperty(JSContext *cx, jsid id)
    1226                 : {
    1227         8428130 :     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
    1228         8428130 :     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
    1229         8428130 :     JS_ASSERT(!unknownProperties());
    1230                 : 
    1231                 :     Property *prop = HashSetLookup<jsid,Property,Property>
    1232         8428130 :         (propertySet, basePropertyCount(), id);
    1233                 : 
    1234         8428130 :     return prop ? &prop->types : NULL;
    1235                 : }
    1236                 : 
    1237                 : inline unsigned
    1238         2452812 : TypeObject::getPropertyCount()
    1239                 : {
    1240         2452812 :     uint32_t count = basePropertyCount();
    1241         2452812 :     if (count > SET_ARRAY_SIZE)
    1242            2354 :         return HashSetCapacity(count);
    1243         2450458 :     return count;
    1244                 : }
    1245                 : 
    1246                 : inline Property *
    1247           11165 : TypeObject::getProperty(unsigned i)
    1248                 : {
    1249           11165 :     JS_ASSERT(i < getPropertyCount());
    1250           11165 :     if (basePropertyCount() == 1) {
    1251            3371 :         JS_ASSERT(i == 0);
    1252            3371 :         return (Property *) propertySet;
    1253                 :     }
    1254            7794 :     return propertySet[i];
    1255                 : }
    1256                 : 
    1257                 : inline void
    1258          248419 : TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
    1259                 : {
    1260          248419 :     TypeObjectFlags flags = 0;
    1261                 : 
    1262          248419 :     switch (key) {
    1263                 :       case JSProto_Function:
    1264           13763 :         JS_ASSERT(isFunction());
    1265                 :         /* FALLTHROUGH */
    1266                 : 
    1267                 :       case JSProto_Object:
    1268                 :         flags = OBJECT_FLAG_NON_DENSE_ARRAY
    1269                 :               | OBJECT_FLAG_NON_PACKED_ARRAY
    1270          239431 :               | OBJECT_FLAG_NON_TYPED_ARRAY;
    1271          239431 :         break;
    1272                 : 
    1273                 :       case JSProto_Array:
    1274            8031 :         flags = OBJECT_FLAG_NON_TYPED_ARRAY;
    1275            8031 :         break;
    1276                 : 
    1277                 :       default:
    1278                 :         /* :XXX: abstract */
    1279               0 :         JS_ASSERT(key == JSProto_Int8Array ||
    1280                 :                   key == JSProto_Uint8Array ||
    1281                 :                   key == JSProto_Int16Array ||
    1282                 :                   key == JSProto_Uint16Array ||
    1283                 :                   key == JSProto_Int32Array ||
    1284                 :                   key == JSProto_Uint32Array ||
    1285                 :                   key == JSProto_Float32Array ||
    1286                 :                   key == JSProto_Float64Array ||
    1287             957 :                   key == JSProto_Uint8ClampedArray);
    1288                 :         flags = OBJECT_FLAG_NON_DENSE_ARRAY
    1289             957 :               | OBJECT_FLAG_NON_PACKED_ARRAY;
    1290             957 :         break;
    1291                 :     }
    1292                 : 
    1293          248419 :     if (!hasAllFlags(flags))
    1294          151612 :         setFlags(cx, flags);
    1295          248419 : }
    1296                 : 
    1297                 : inline JSObject *
    1298               0 : TypeObject::getGlobal()
    1299                 : {
    1300               0 :     if (singleton)
    1301               0 :         return &singleton->global();
    1302               0 :     if (interpretedFunction && interpretedFunction->script()->compileAndGo)
    1303               0 :         return &interpretedFunction->global();
    1304               0 :     return NULL;
    1305                 : }
    1306                 : 
    1307                 : inline void
    1308        13456089 : TypeObject::writeBarrierPre(TypeObject *type)
    1309                 : {
    1310                 : #ifdef JSGC_INCREMENTAL
    1311        13456089 :     if (!type)
    1312         1868411 :         return;
    1313                 : 
    1314        11587678 :     JSCompartment *comp = type->compartment();
    1315        11587678 :     if (comp->needsBarrier()) {
    1316            2537 :         TypeObject *tmp = type;
    1317            2537 :         MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
    1318            2537 :         JS_ASSERT(tmp == type);
    1319                 :     }
    1320                 : #endif
    1321                 : }
    1322                 : 
    1323                 : inline void
    1324        23077179 : TypeObject::writeBarrierPost(TypeObject *type, void *addr)
    1325                 : {
    1326        23077179 : }
    1327                 : 
    1328                 : inline void
    1329        57306806 : TypeObject::readBarrier(TypeObject *type)
    1330                 : {
    1331                 : #ifdef JSGC_INCREMENTAL
    1332        57306806 :     JSCompartment *comp = type->compartment();
    1333        57306806 :     if (comp->needsBarrier()) {
    1334           14722 :         TypeObject *tmp = type;
    1335           14722 :         MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
    1336           14722 :         JS_ASSERT(tmp == type);
    1337                 :     }
    1338                 : #endif
    1339        57306806 : }
    1340                 : 
    1341                 : inline void
    1342             620 : TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
    1343                 : {
    1344                 : #ifdef JSGC_INCREMENTAL
    1345             620 :     if (!newScript)
    1346             580 :         return;
    1347                 : 
    1348              40 :     JSCompartment *comp = newScript->fun->compartment();
    1349              40 :     if (comp->needsBarrier()) {
    1350               0 :         MarkObject(comp->barrierTracer(), &newScript->fun, "write barrier");
    1351               0 :         MarkShape(comp->barrierTracer(), &newScript->shape, "write barrier");
    1352                 :     }
    1353                 : #endif
    1354                 : }
    1355                 : 
    1356                 : inline void
    1357             620 : TypeNewScript::writeBarrierPost(TypeNewScript *newScript, void *addr)
    1358                 : {
    1359             620 : }
    1360                 : 
    1361                 : inline
    1362          145677 : Property::Property(jsid id)
    1363          145677 :   : id(id)
    1364                 : {
    1365          145677 : }
    1366                 : 
    1367                 : inline
    1368            9560 : Property::Property(const Property &o)
    1369            9560 :   : id(o.id.get()), types(o.types)
    1370                 : {
    1371            9560 : }
    1372                 : 
    1373                 : } } /* namespace js::types */
    1374                 : 
    1375                 : inline bool
    1376       110786089 : JSScript::ensureHasTypes(JSContext *cx)
    1377                 : {
    1378       110786089 :     return types || makeTypes(cx);
    1379                 : }
    1380                 : 
    1381                 : inline bool
    1382       110692410 : JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
    1383                 : {
    1384       110692410 :     JSScript *self = this;
    1385                 : 
    1386       110692410 :     if (!self->ensureHasTypes(cx))
    1387               0 :         return false;
    1388       110692410 :     if (!self->types->hasScope()) {
    1389          941718 :         js::CheckRoot root(cx, &self);
    1390          941718 :         js::RootObject objRoot(cx, &scope);
    1391          470859 :         if (!js::types::TypeScript::SetScope(cx, self, scope))
    1392               0 :             return false;
    1393                 :     }
    1394       110692410 :     if (!self->hasAnalysis() && !self->makeAnalysis(cx))
    1395               0 :         return false;
    1396       110692410 :     JS_ASSERT(self->analysis()->ranBytecode());
    1397       110692410 :     return true;
    1398                 : }
    1399                 : 
    1400                 : inline bool
    1401         4464633 : JSScript::ensureRanInference(JSContext *cx)
    1402                 : {
    1403         4464633 :     if (!ensureRanAnalysis(cx, NULL))
    1404               0 :         return false;
    1405         4464633 :     if (!analysis()->ranInference()) {
    1406           77564 :         js::types::AutoEnterTypeInference enter(cx);
    1407           38782 :         analysis()->analyzeTypes(cx);
    1408                 :     }
    1409         4464633 :     return !analysis()->OOM() &&
    1410         4464633 :         !cx->compartment->types.pendingNukeTypes;
    1411                 : }
    1412                 : 
    1413                 : inline bool
    1414      2060068643 : JSScript::hasAnalysis()
    1415                 : {
    1416      2060068643 :     return types && types->analysis;
    1417                 : }
    1418                 : 
    1419                 : inline js::analyze::ScriptAnalysis *
    1420      1079697474 : JSScript::analysis()
    1421                 : {
    1422      1079697474 :     JS_ASSERT(hasAnalysis());
    1423      1079697474 :     return types->analysis;
    1424                 : }
    1425                 : 
    1426                 : inline void
    1427         8105181 : JSScript::clearAnalysis()
    1428                 : {
    1429         8105181 :     if (types)
    1430         2401904 :         types->analysis = NULL;
    1431         8105181 : }
    1432                 : 
    1433                 : inline void
    1434                 : js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
    1435                 :                                            js::types::Type type)
    1436                 : {
    1437                 :     js::types::TypeSet *pushed = pushedTypes(offset, which);
    1438                 :     pushed->addType(cx, type);
    1439                 : }
    1440                 : 
    1441                 : inline js::types::TypeObject *
    1442         3072009 : JSCompartment::getEmptyType(JSContext *cx)
    1443                 : {
    1444         3072009 :     if (!emptyTypeObject)
    1445           25666 :         emptyTypeObject = types.newTypeObject(cx, NULL, JSProto_Object, NULL, true);
    1446         3072009 :     return emptyTypeObject;
    1447                 : }
    1448                 : 
    1449                 : #endif // jsinferinlines_h___

Generated by: LCOV version 1.7