LCOV - code coverage report
Current view: directory - js/src - jsinferinlines.h (source / functions) Found Hit Coverage
Test: app.info Lines: 662 621 93.8 %
Date: 2012-04-07 Functions: 104 102 98.1 %

       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        41228106 : Type::ObjectType(JSObject *obj)
      64                 : {
      65        41228106 :     if (obj->hasSingletonType())
      66        10252859 :         return Type(uintptr_t(obj) | 1);
      67        30975247 :     return Type(uintptr_t(obj->type()));
      68                 : }
      69                 : 
      70                 : /* static */ inline Type
      71          737572 : Type::ObjectType(TypeObject *obj)
      72                 : {
      73          737572 :     if (obj->singleton)
      74          132880 :         return Type(uintptr_t(obj->singleton.get()) | 1);
      75          604692 :     return Type(uintptr_t(obj));
      76                 : }
      77                 : 
      78                 : /* static */ inline Type
      79          583578 : Type::ObjectType(TypeObjectKey *obj)
      80                 : {
      81          583578 :     return Type(uintptr_t(obj));
      82                 : }
      83                 : 
      84                 : inline Type
      85       166902888 : GetValueType(JSContext *cx, const Value &val)
      86                 : {
      87       166902888 :     JS_ASSERT(cx->typeInferenceEnabled());
      88       166902888 :     if (val.isDouble())
      89        11836001 :         return Type::DoubleType();
      90       155066887 :     if (val.isObject())
      91        40406626 :         return Type::ObjectType(&val.toObject());
      92       114660261 :     return Type::PrimitiveType(val.extractNonDoubleType());
      93                 : }
      94                 : 
      95                 : inline TypeFlags
      96       117733860 : PrimitiveTypeFlag(JSValueType type)
      97                 : {
      98       117733860 :     switch (type) {
      99                 :       case JSVAL_TYPE_UNDEFINED:
     100        11228146 :         return TYPE_FLAG_UNDEFINED;
     101                 :       case JSVAL_TYPE_NULL:
     102         3498205 :         return TYPE_FLAG_NULL;
     103                 :       case JSVAL_TYPE_BOOLEAN:
     104         2219644 :         return TYPE_FLAG_BOOLEAN;
     105                 :       case JSVAL_TYPE_INT32:
     106        79909397 :         return TYPE_FLAG_INT32;
     107                 :       case JSVAL_TYPE_DOUBLE:
     108        12239144 :         return TYPE_FLAG_DOUBLE;
     109                 :       case JSVAL_TYPE_STRING:
     110         8569890 :         return TYPE_FLAG_STRING;
     111                 :       case JSVAL_TYPE_MAGIC:
     112           69434 :         return TYPE_FLAG_LAZYARGS;
     113                 :       default:
     114               0 :         JS_NOT_REACHED("Bad type");
     115                 :         return 0;
     116                 :     }
     117                 : }
     118                 : 
     119                 : inline JSValueType
     120          774498 : TypeFlagPrimitive(TypeFlags flags)
     121                 : {
     122          774498 :     switch (flags) {
     123                 :       case TYPE_FLAG_UNDEFINED:
     124          127742 :         return JSVAL_TYPE_UNDEFINED;
     125                 :       case TYPE_FLAG_NULL:
     126            7297 :         return JSVAL_TYPE_NULL;
     127                 :       case TYPE_FLAG_BOOLEAN:
     128            8896 :         return JSVAL_TYPE_BOOLEAN;
     129                 :       case TYPE_FLAG_INT32:
     130          546520 :         return JSVAL_TYPE_INT32;
     131                 :       case TYPE_FLAG_DOUBLE:
     132           13054 :         return JSVAL_TYPE_DOUBLE;
     133                 :       case TYPE_FLAG_STRING:
     134           70560 :         return JSVAL_TYPE_STRING;
     135                 :       case TYPE_FLAG_LAZYARGS:
     136             429 :         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        73674843 : MakeTypeId(JSContext *cx, jsid id)
     150                 : {
     151        73674843 :     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        73674843 :     if (JSID_IS_INT(id))
     158         1475390 :         return JSID_VOID;
     159                 : 
     160                 :     /*
     161                 :      * Check for numeric strings, as in js_StringIsIndex, but allow negative
     162                 :      * and overflowing integers.
     163                 :      */
     164        72199453 :     if (JSID_IS_STRING(id)) {
     165        41507281 :         JSFlatString *str = JSID_TO_FLAT_STRING(id);
     166        41507281 :         const jschar *cp = str->getCharsZ(cx);
     167        41507281 :         if (JS7_ISDEC(*cp) || *cp == '-') {
     168           25305 :             cp++;
     169           56280 :             while (JS7_ISDEC(*cp))
     170            5670 :                 cp++;
     171           25305 :             if (*cp == 0)
     172            2905 :                 return JSID_VOID;
     173                 :         }
     174        41504376 :         return id;
     175                 :     }
     176                 : 
     177        30692172 :     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          194854 : TypeIdString(jsid id)
     185                 : {
     186                 : #ifdef DEBUG
     187          194854 :     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                 :     FreeOp *freeOp;
     206                 :     JSCompartment *compartment;
     207                 :     bool oldActiveAnalysis;
     208                 :     bool oldActiveInference;
     209                 : 
     210       955923595 :     AutoEnterTypeInference(JSContext *cx, bool compiling = false)
     211                 :     {
     212       955923595 :         JS_ASSERT_IF(!compiling, cx->compartment->types.inferenceEnabled);
     213       955923595 :         init(cx->runtime->defaultFreeOp(), cx->compartment);
     214       955923595 :     }
     215                 : 
     216           34485 :     AutoEnterTypeInference(FreeOp *fop, JSCompartment *comp)
     217                 :     {
     218           34485 :         init(fop, comp);
     219           34485 :     }
     220                 : 
     221       955958080 :     ~AutoEnterTypeInference()
     222                 :     {
     223       955958080 :         compartment->activeAnalysis = oldActiveAnalysis;
     224       955958080 :         compartment->activeInference = oldActiveInference;
     225                 : 
     226                 :         /*
     227                 :          * If there are no more type inference activations on the stack,
     228                 :          * process any triggered recompilations. Note that we should not be
     229                 :          * invoking any scripted code while type inference is running.
     230                 :          * :TODO: assert this.
     231                 :          */
     232       955958080 :         if (!compartment->activeInference) {
     233       955797074 :             TypeCompartment *types = &compartment->types;
     234       955797074 :             if (types->pendingNukeTypes)
     235               0 :                 types->nukeTypes(freeOp);
     236       955797074 :             else if (types->pendingRecompiles)
     237           32935 :                 types->processPendingRecompiles(freeOp);
     238                 :         }
     239       955958080 :     }
     240                 : 
     241                 :   private:
     242       955958080 :     void init(FreeOp *fop, JSCompartment *comp) {
     243       955958080 :         freeOp = fop;
     244       955958080 :         compartment = comp;
     245       955958080 :         oldActiveAnalysis = compartment->activeAnalysis;
     246       955958080 :         oldActiveInference = compartment->activeInference;
     247       955958080 :         compartment->activeAnalysis = true;
     248       955958080 :         compartment->activeInference = true;
     249       955958080 :     }
     250                 : };
     251                 : 
     252                 : /*
     253                 :  * Structure marking the currently compiled script, for constraints which can
     254                 :  * trigger recompilation.
     255                 :  */
     256                 : struct AutoEnterCompilation
     257                 : {
     258                 :     RecompileInfo &info;
     259                 : 
     260           95862 :     AutoEnterCompilation(JSContext *cx, JSScript *script, bool constructing, unsigned chunkIndex)
     261           95862 :         : info(cx->compartment->types.compiledInfo)
     262                 :     {
     263           95862 :         JS_ASSERT(!info.script);
     264           95862 :         info.script = script;
     265           95862 :         info.constructing = constructing;
     266           95862 :         info.chunkIndex = chunkIndex;
     267           95862 :     }
     268                 : 
     269           95862 :     ~AutoEnterCompilation()
     270                 :     {
     271           95862 :         JS_ASSERT(info.script);
     272           95862 :         info.script = NULL;
     273           95862 :         info.constructing = false;
     274           95862 :         info.chunkIndex = 0;
     275           95862 :     }
     276                 : };
     277                 : 
     278                 : /////////////////////////////////////////////////////////////////////
     279                 : // Interface functions
     280                 : /////////////////////////////////////////////////////////////////////
     281                 : 
     282                 : /*
     283                 :  * These functions check whether inference is enabled before performing some
     284                 :  * action on the type state. To avoid checking cx->typeInferenceEnabled()
     285                 :  * everywhere, it is generally preferred to use one of these functions or
     286                 :  * a type function on JSScript to perform inference operations.
     287                 :  */
     288                 : 
     289                 : /*
     290                 :  * Get the default 'new' object for a given standard class, per the currently
     291                 :  * active global.
     292                 :  */
     293                 : inline TypeObject *
     294           62852 : GetTypeNewObject(JSContext *cx, JSProtoKey key)
     295                 : {
     296                 :     JSObject *proto;
     297           62852 :     if (!js_GetClassPrototype(cx, NULL, key, &proto, NULL))
     298               0 :         return NULL;
     299           62852 :     return proto->getNewType(cx);
     300                 : }
     301                 : 
     302                 : /* Get a type object for the immediate allocation site within a native. */
     303                 : inline TypeObject *
     304          108378 : GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
     305                 : {
     306          108378 :     if (cx->typeInferenceEnabled()) {
     307                 :         jsbytecode *pc;
     308           54379 :         JSScript *script = cx->stack.currentScript(&pc);
     309           54379 :         if (script)
     310           54254 :             return TypeScript::InitObject(cx, script, pc, key);
     311                 :     }
     312           54124 :     return GetTypeNewObject(cx, key);
     313                 : }
     314                 : 
     315                 : /*
     316                 :  * When using a custom iterator within the initialization of a 'for in' loop,
     317                 :  * mark the iterator values as unknown.
     318                 :  */
     319                 : inline void
     320            4363 : MarkIteratorUnknown(JSContext *cx)
     321                 : {
     322                 :     extern void MarkIteratorUnknownSlow(JSContext *cx);
     323                 : 
     324            4363 :     if (cx->typeInferenceEnabled())
     325            2396 :         MarkIteratorUnknownSlow(cx);
     326            4363 : }
     327                 : 
     328                 : /*
     329                 :  * Monitor a javascript call, either on entry to the interpreter or made
     330                 :  * from within the interpreter.
     331                 :  */
     332                 : inline void
     333        21873273 : TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
     334                 : {
     335                 :     extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
     336                 :                                     const CallArgs &args, bool constructing);
     337                 : 
     338        21873273 :     JSObject *callee = &args.callee();
     339        21873273 :     if (callee->isFunction()) {
     340        21873273 :         JSFunction *fun = callee->toFunction();
     341        21873273 :         if (fun->isInterpreted()) {
     342        21873273 :             JSScript *script = fun->script();
     343        21873273 :             if (!script->ensureRanAnalysis(cx, fun->environment()))
     344               0 :                 return;
     345        21873273 :             if (cx->typeInferenceEnabled())
     346        12965925 :                 TypeMonitorCallSlow(cx, callee, args, constructing);
     347                 :         }
     348                 :     }
     349                 : }
     350                 : 
     351                 : inline bool
     352        72113711 : TrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
     353                 : {
     354        72113711 :     if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
     355        51458296 :         return false;
     356                 : 
     357        20655415 :     if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id))
     358         7090045 :         return false;
     359                 : 
     360        13565370 :     return true;
     361                 : }
     362                 : 
     363                 : /* Add a possible type for a property of obj. */
     364                 : inline void
     365         1242527 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, Type type)
     366                 : {
     367         1242527 :     if (cx->typeInferenceEnabled())
     368          688815 :         id = MakeTypeId(cx, id);
     369         1242527 :     if (TrackPropertyTypes(cx, obj, id))
     370          272259 :         obj->type()->addPropertyType(cx, id, type);
     371         1242527 : }
     372                 : 
     373                 : inline void
     374        58164129 : AddTypePropertyId(JSContext *cx, JSObject *obj, jsid id, const Value &value)
     375                 : {
     376        58164129 :     if (cx->typeInferenceEnabled())
     377        28141961 :         id = MakeTypeId(cx, id);
     378        58164129 :     if (TrackPropertyTypes(cx, obj, id))
     379        13018142 :         obj->type()->addPropertyType(cx, id, value);
     380        58164129 : }
     381                 : 
     382                 : inline void
     383           32848 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type)
     384                 : {
     385           32848 :     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
     386           17870 :         obj->addPropertyType(cx, name, type);
     387           32848 : }
     388                 : 
     389                 : inline void
     390               0 : AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value)
     391                 : {
     392               0 :     if (cx->typeInferenceEnabled() && !obj->unknownProperties())
     393               0 :         obj->addPropertyType(cx, name, value);
     394               0 : }
     395                 : 
     396                 : /* Set one or more dynamic flags on a type object. */
     397                 : inline void
     398         3133320 : MarkTypeObjectFlags(JSContext *cx, JSObject *obj, TypeObjectFlags flags)
     399                 : {
     400         3133320 :     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags))
     401            5954 :         obj->type()->setFlags(cx, flags);
     402         3133320 : }
     403                 : 
     404                 : /*
     405                 :  * Mark all properties of a type object as unknown. If markSetsUnknown is set,
     406                 :  * scan the entire compartment and mark all type sets containing it as having
     407                 :  * an unknown object. This is needed for correctness in dealing with mutable
     408                 :  * __proto__, which can change the type of an object dynamically.
     409                 :  */
     410                 : inline void
     411         3801202 : MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
     412                 :                                 bool markSetsUnknown = false)
     413                 : {
     414         3801202 :     if (cx->typeInferenceEnabled()) {
     415         2278024 :         if (!obj->unknownProperties())
     416           13710 :             obj->markUnknown(cx);
     417         2278024 :         if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
     418              65 :             cx->compartment->types.markSetsUnknown(cx, obj);
     419                 :     }
     420         3801202 : }
     421                 : 
     422                 : /*
     423                 :  * Mark any property which has been deleted or configured to be non-writable or
     424                 :  * have a getter/setter.
     425                 :  */
     426                 : inline void
     427        12707055 : MarkTypePropertyConfigured(JSContext *cx, JSObject *obj, jsid id)
     428                 : {
     429        12707055 :     if (cx->typeInferenceEnabled())
     430         7021114 :         id = MakeTypeId(cx, id);
     431        12707055 :     if (TrackPropertyTypes(cx, obj, id))
     432          274969 :         obj->type()->markPropertyConfigured(cx, id);
     433        12707055 : }
     434                 : 
     435                 : /* Mark a state change on a particular object. */
     436                 : inline void
     437           23700 : MarkObjectStateChange(JSContext *cx, JSObject *obj)
     438                 : {
     439           23700 :     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
     440           13065 :         obj->type()->markStateChange(cx);
     441           23700 : }
     442                 : 
     443                 : /*
     444                 :  * For an array or object which has not yet escaped and been referenced elsewhere,
     445                 :  * pick a new type based on the object's current contents.
     446                 :  */
     447                 : 
     448                 : inline void
     449            3258 : FixArrayType(JSContext *cx, JSObject *obj)
     450                 : {
     451            3258 :     if (cx->typeInferenceEnabled())
     452            1810 :         cx->compartment->types.fixArrayType(cx, obj);
     453            3258 : }
     454                 : 
     455                 : inline void
     456            2569 : FixObjectType(JSContext *cx, JSObject *obj)
     457                 : {
     458            2569 :     if (cx->typeInferenceEnabled())
     459            1425 :         cx->compartment->types.fixObjectType(cx, obj);
     460            2569 : }
     461                 : 
     462                 : /* Interface helpers for JSScript */
     463                 : extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
     464                 : extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
     465                 : 
     466                 : inline bool
     467          502154 : UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
     468                 : {
     469          502484 :     return fp->isConstructing() && cx->typeInferenceEnabled() &&
     470             346 :            fp->prev() && fp->prev()->isScriptFrame() &&
     471          502830 :            UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
     472                 : }
     473                 : 
     474                 : /////////////////////////////////////////////////////////////////////
     475                 : // Script interface functions
     476                 : /////////////////////////////////////////////////////////////////////
     477                 : 
     478                 : inline
     479          154005 : TypeScript::TypeScript()
     480                 : {
     481          154005 :     this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
     482          154005 : }
     483                 : 
     484                 : /* static */ inline unsigned
     485          203037 : TypeScript::NumTypeSets(JSScript *script)
     486                 : {
     487          203037 :     return script->nTypeSets + analyze::TotalSlots(script);
     488                 : }
     489                 : 
     490                 : /* static */ inline TypeSet *
     491          131193 : TypeScript::ReturnTypes(JSScript *script)
     492                 : {
     493          131193 :     return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
     494                 : }
     495                 : 
     496                 : /* static */ inline TypeSet *
     497        29343419 : TypeScript::ThisTypes(JSScript *script)
     498                 : {
     499        29343419 :     return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
     500                 : }
     501                 : 
     502                 : /*
     503                 :  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
     504                 :  * only the initial type of the variable (e.g. passed values for argTypes,
     505                 :  * or undefined for localTypes) and not types from subsequent assignments.
     506                 :  */
     507                 : 
     508                 : /* static */ inline TypeSet *
     509        45082852 : TypeScript::ArgTypes(JSScript *script, unsigned i)
     510                 : {
     511        45082852 :     JS_ASSERT(i < script->function()->nargs);
     512        45082852 :     return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
     513                 : }
     514                 : 
     515                 : /* static */ inline TypeSet *
     516          109170 : TypeScript::LocalTypes(JSScript *script, unsigned i)
     517                 : {
     518          109170 :     JS_ASSERT(i < script->nfixed);
     519          109170 :     return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
     520                 : }
     521                 : 
     522                 : /* static */ inline TypeSet *
     523          337376 : TypeScript::SlotTypes(JSScript *script, unsigned slot)
     524                 : {
     525          337376 :     JS_ASSERT(slot < js::analyze::TotalSlots(script));
     526          337376 :     return script->types->typeArray() + script->nTypeSets + slot;
     527                 : }
     528                 : 
     529                 : /* static */ inline TypeObject *
     530            8070 : TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
     531                 : {
     532                 :     JSObject *proto;
     533            8070 :     if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
     534               0 :         return NULL;
     535            8070 :     return proto->getNewType(cx);
     536                 : }
     537                 : 
     538                 : struct AllocationSiteKey {
     539                 :     JSScript *script;
     540                 : 
     541                 :     uint32_t offset : 24;
     542                 :     JSProtoKey kind : 8;
     543                 : 
     544                 :     static const uint32_t OFFSET_LIMIT = (1 << 23);
     545                 : 
     546         1244003 :     AllocationSiteKey() { PodZero(this); }
     547                 : 
     548                 :     typedef AllocationSiteKey Lookup;
     549                 : 
     550         1017262 :     static inline uint32_t hash(AllocationSiteKey key) {
     551         1017262 :         return uint32_t(size_t(key.script->code + key.offset)) ^ key.kind;
     552                 :     }
     553                 : 
     554          996425 :     static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
     555          996425 :         return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
     556                 :     }
     557                 : };
     558                 : 
     559                 : /* static */ inline TypeObject *
     560         1017738 : TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
     561                 : {
     562         1017738 :     JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc));
     563                 : 
     564                 :     /* :XXX: Limit script->length so we don't need to check the offset up front? */
     565         1017738 :     uint32_t offset = pc - script->code;
     566                 : 
     567         1017738 :     if (!cx->typeInferenceEnabled() || !script->hasGlobal() || offset >= AllocationSiteKey::OFFSET_LIMIT)
     568            8728 :         return GetTypeNewObject(cx, kind);
     569                 : 
     570         1009010 :     AllocationSiteKey key;
     571         1009010 :     key.script = script;
     572         1009010 :     key.offset = offset;
     573         1009010 :     key.kind = kind;
     574                 : 
     575         1009010 :     if (!cx->compartment->types.allocationSiteTable)
     576            4333 :         return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
     577                 : 
     578         1004677 :     AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(key);
     579                 : 
     580         1004677 :     if (p)
     581          996425 :         return p->value;
     582            8252 :     return cx->compartment->types.newAllocationSiteTypeObject(cx, key);
     583                 : }
     584                 : 
     585                 : /* Set the type to use for obj according to the site it was allocated at. */
     586                 : static inline bool
     587         1870897 : SetInitializerObjectType(JSContext *cx, JSScript *script, jsbytecode *pc, JSObject *obj)
     588                 : {
     589         1870897 :     if (!cx->typeInferenceEnabled())
     590          944359 :         return true;
     591                 : 
     592          926538 :     if (UseNewTypeForInitializer(cx, script, pc)) {
     593            2660 :         if (!obj->setSingletonType(cx))
     594               0 :             return false;
     595                 : 
     596                 :         /*
     597                 :          * Inference does not account for types of run-once initializer
     598                 :          * objects, as these may not be created until after the script
     599                 :          * has been analyzed.
     600                 :          */
     601            2660 :         TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
     602                 :     } else {
     603          923878 :         JSProtoKey key = obj->isDenseArray() ? JSProto_Array : JSProto_Object;
     604          923878 :         types::TypeObject *type = TypeScript::InitObject(cx, script, pc, key);
     605          923878 :         if (!type)
     606               0 :             return false;
     607          923878 :         obj->setType(type);
     608                 :     }
     609                 : 
     610          926538 :     return true;
     611                 : }
     612                 : 
     613                 : /* static */ inline void
     614       149850692 : TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
     615                 : {
     616       149850692 :     if (cx->typeInferenceEnabled())
     617        75873907 :         TypeMonitorResult(cx, script, pc, rval);
     618       149850692 : }
     619                 : 
     620                 : /* static */ inline void
     621         1398041 : TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
     622                 : {
     623         1398041 :     if (cx->typeInferenceEnabled())
     624          530616 :         TypeDynamicResult(cx, script, pc, Type::DoubleType());
     625         1398041 : }
     626                 : 
     627                 : /* static */ inline void
     628          509356 : TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
     629                 : {
     630          509356 :     if (cx->typeInferenceEnabled())
     631          282975 :         TypeDynamicResult(cx, script, pc, Type::StringType());
     632          509356 : }
     633                 : 
     634                 : /* static */ inline void
     635            2826 : TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
     636                 : {
     637            2826 :     if (cx->typeInferenceEnabled())
     638            1570 :         TypeDynamicResult(cx, script, pc, Type::UnknownType());
     639            2826 : }
     640                 : 
     641                 : /* static */ inline void
     642         2619521 : TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
     643                 : {
     644         2619521 :     *script = cx->fp()->script();
     645         2619521 :     *pc = cx->regs().pc;
     646         2619521 : }
     647                 : 
     648                 : /* static */ inline void
     649          999574 : TypeScript::MonitorOverflow(JSContext *cx)
     650                 : {
     651                 :     JSScript *script;
     652                 :     jsbytecode *pc;
     653          999574 :     GetPcScript(cx, &script, &pc);
     654          999574 :     MonitorOverflow(cx, script, pc);
     655          999574 : }
     656                 : 
     657                 : /* static */ inline void
     658          118047 : TypeScript::MonitorString(JSContext *cx)
     659                 : {
     660                 :     JSScript *script;
     661                 :     jsbytecode *pc;
     662          118047 :     GetPcScript(cx, &script, &pc);
     663          118047 :     MonitorString(cx, script, pc);
     664          118047 : }
     665                 : 
     666                 : /* static */ inline void
     667             874 : TypeScript::MonitorUnknown(JSContext *cx)
     668                 : {
     669                 :     JSScript *script;
     670                 :     jsbytecode *pc;
     671             874 :     GetPcScript(cx, &script, &pc);
     672             874 :     MonitorUnknown(cx, script, pc);
     673             874 : }
     674                 : 
     675                 : /* static */ inline void
     676                 : TypeScript::Monitor(JSContext *cx, const js::Value &rval)
     677                 : {
     678                 :     JSScript *script;
     679                 :     jsbytecode *pc;
     680                 :     GetPcScript(cx, &script, &pc);
     681                 :     Monitor(cx, script, pc, rval);
     682                 : }
     683                 : 
     684                 : /* static */ inline void
     685        13161666 : TypeScript::MonitorAssign(JSContext *cx, JSObject *obj, jsid id)
     686                 : {
     687        13161666 :     if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
     688                 :         /*
     689                 :          * Mark as unknown any object which has had dynamic assignments to
     690                 :          * non-integer properties at SETELEM opcodes. This avoids making large
     691                 :          * numbers of type properties for hashmap-style objects. We don't need
     692                 :          * to do this for objects with singleton type, because type properties
     693                 :          * are only constructed for them when analyzed scripts depend on those
     694                 :          * specific properties.
     695                 :          */
     696                 :         uint32_t i;
     697         5995489 :         if (js_IdIsIndex(id, &i))
     698         5592969 :             return;
     699          402520 :         MarkTypeObjectUnknownProperties(cx, obj->type());
     700                 :     }
     701                 : }
     702                 : 
     703                 : /* static */ inline void
     704        12519334 : TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
     705                 : {
     706        12519334 :     if (!cx->typeInferenceEnabled())
     707               0 :         return;
     708        12519334 :     JS_ASSERT(script->types);
     709                 : 
     710                 :     /* Analyze the script regardless if -a was used. */
     711        12519334 :     bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS);
     712                 : 
     713        12519334 :     if (!ThisTypes(script)->hasType(type) || analyze) {
     714         8521978 :         AutoEnterTypeInference enter(cx);
     715                 : 
     716                 :         InferSpew(ISpewOps, "externalType: setThis #%u: %s",
     717         4260989 :                   script->id(), TypeString(type));
     718         4260989 :         ThisTypes(script)->addType(cx, type);
     719                 : 
     720         4260989 :         if (analyze && script->types->hasScope())
     721         4210936 :             script->ensureRanInference(cx);
     722                 :     }
     723                 : }
     724                 : 
     725                 : /* static */ inline void
     726        11806672 : TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
     727                 : {
     728        11806672 :     if (cx->typeInferenceEnabled())
     729        11738645 :         SetThis(cx, script, GetValueType(cx, value));
     730        11806672 : }
     731                 : 
     732                 : /* static */ inline void
     733           10731 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
     734                 : {
     735           10731 :     if (!cx->typeInferenceEnabled())
     736               0 :         return;
     737           10731 :     JS_ASSERT(script->types);
     738                 : 
     739           10731 :     if (!LocalTypes(script, local)->hasType(type)) {
     740             908 :         AutoEnterTypeInference enter(cx);
     741                 : 
     742                 :         InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
     743             454 :                   script->id(), local, TypeString(type));
     744             454 :         LocalTypes(script, local)->addType(cx, type);
     745                 :     }
     746                 : }
     747                 : 
     748                 : /* static */ inline void
     749           18559 : TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
     750                 : {
     751           18559 :     if (cx->typeInferenceEnabled()) {
     752           10731 :         Type type = GetValueType(cx, value);
     753           10731 :         SetLocal(cx, script, local, type);
     754                 :     }
     755           18559 : }
     756                 : 
     757                 : /* static */ inline void
     758        20696700 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
     759                 : {
     760        20696700 :     if (!cx->typeInferenceEnabled())
     761               0 :         return;
     762        20696700 :     JS_ASSERT(script->types);
     763                 : 
     764        20696700 :     if (!ArgTypes(script, arg)->hasType(type)) {
     765          165882 :         AutoEnterTypeInference enter(cx);
     766                 : 
     767                 :         InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
     768           82941 :                   script->id(), arg, TypeString(type));
     769           82941 :         ArgTypes(script, arg)->addType(cx, type);
     770                 :     }
     771                 : }
     772                 : 
     773                 : /* static */ inline void
     774        20697199 : TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
     775                 : {
     776        20697199 :     if (cx->typeInferenceEnabled()) {
     777        20696700 :         Type type = GetValueType(cx, value);
     778        20696700 :         SetArgument(cx, script, arg, type);
     779                 :     }
     780        20697199 : }
     781                 : 
     782                 : void
     783           70791 : TypeScript::trace(JSTracer *trc)
     784                 : {
     785           70791 :     if (hasScope() && global)
     786           67363 :         gc::MarkObject(trc, &global, "script_global");
     787                 : 
     788                 :     /* Note: nesting does not keep anything alive. */
     789           70791 : }
     790                 : 
     791                 : /////////////////////////////////////////////////////////////////////
     792                 : // TypeCompartment
     793                 : /////////////////////////////////////////////////////////////////////
     794                 : 
     795                 : inline JSCompartment *
     796          157873 : TypeCompartment::compartment()
     797                 : {
     798          157873 :     return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
     799                 : }
     800                 : 
     801                 : inline void
     802         3160284 : TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type)
     803                 : {
     804         3160284 :     JS_ASSERT(this == &cx->compartment->types);
     805         3160284 :     JS_ASSERT(!cx->runtime->gcRunning);
     806                 : 
     807                 :     InferSpew(ISpewOps, "pending: %sC%p%s %s",
     808                 :               InferSpewColor(constraint), constraint, InferSpewColorReset(),
     809         3160284 :               TypeString(type));
     810                 : 
     811         3160284 :     if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
     812               0 :         return;
     813                 : 
     814         3160284 :     PendingWork &pending = pendingArray[pendingCount++];
     815         3160284 :     pending.constraint = constraint;
     816         3160284 :     pending.source = source;
     817         3160284 :     pending.type = type;
     818                 : }
     819                 : 
     820                 : inline void
     821         4699928 : TypeCompartment::resolvePending(JSContext *cx)
     822                 : {
     823         4699928 :     JS_ASSERT(this == &cx->compartment->types);
     824                 : 
     825         4699928 :     if (resolving) {
     826                 :         /* There is an active call further up resolving the worklist. */
     827         1222924 :         return;
     828                 :     }
     829                 : 
     830         3477004 :     resolving = true;
     831                 : 
     832                 :     /* Handle all pending type registrations. */
     833        10114292 :     while (pendingCount) {
     834         3160284 :         const PendingWork &pending = pendingArray[--pendingCount];
     835                 :         InferSpew(ISpewOps, "resolve: %sC%p%s %s",
     836                 :                   InferSpewColor(pending.constraint), pending.constraint,
     837         3160284 :                   InferSpewColorReset(), TypeString(pending.type));
     838         3160284 :         pending.constraint->newType(cx, pending.source, pending.type);
     839                 :     }
     840                 : 
     841         3477004 :     resolving = false;
     842                 : }
     843                 : 
     844                 : /////////////////////////////////////////////////////////////////////
     845                 : // TypeSet
     846                 : /////////////////////////////////////////////////////////////////////
     847                 : 
     848                 : /*
     849                 :  * The sets of objects and scripts in a type set grow monotonically, are usually
     850                 :  * empty, almost always small, and sometimes big.  For empty or singleton sets,
     851                 :  * the pointer refers directly to the value.  For sets fitting into SET_ARRAY_SIZE,
     852                 :  * an array of this length is used to store the elements.  For larger sets, a hash
     853                 :  * table filled to 25%-50% of capacity is used, with collisions resolved by linear
     854                 :  * probing.  TODO: replace these with jshashtables.
     855                 :  */
     856                 : const unsigned SET_ARRAY_SIZE = 8;
     857                 : 
     858                 : /* Get the capacity of a set with the given element count. */
     859                 : static inline unsigned
     860         4554030 : HashSetCapacity(unsigned count)
     861                 : {
     862         4554030 :     JS_ASSERT(count >= 2);
     863                 : 
     864         4554030 :     if (count <= SET_ARRAY_SIZE)
     865           19715 :         return SET_ARRAY_SIZE;
     866                 : 
     867                 :     unsigned log2;
     868         4534315 :     JS_FLOOR_LOG2(log2, count);
     869         4534315 :     return 1 << (log2 + 2);
     870                 : }
     871                 : 
     872                 : /* Compute the FNV hash for the low 32 bits of v. */
     873                 : template <class T, class KEY>
     874                 : static inline uint32_t
     875         2882738 : HashKey(T v)
     876                 : {
     877         2882738 :     uint32_t nv = KEY::keyBits(v);
     878                 : 
     879         2882738 :     uint32_t hash = 84696351 ^ (nv & 0xff);
     880         2882738 :     hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
     881         2882738 :     hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
     882         2882738 :     return (hash * 16777619) ^ ((nv >> 24) & 0xff);
     883                 : }
     884                 : 
     885                 : /*
     886                 :  * Insert space for an element into the specified set and grow its capacity if needed.
     887                 :  * returned value is an existing or new entry (NULL if new).
     888                 :  */
     889                 : template <class T, class U, class KEY>
     890                 : static U **
     891         1007448 : HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
     892                 : {
     893         1007448 :     unsigned capacity = HashSetCapacity(count);
     894         1007448 :     unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
     895                 : 
     896                 :     /* Whether we are converting from a fixed array to hashtable. */
     897         1007448 :     bool converting = (count == SET_ARRAY_SIZE);
     898                 : 
     899         1007448 :     if (!converting) {
     900         2717699 :         while (values[insertpos] != NULL) {
     901         1211594 :             if (KEY::getKey(values[insertpos]) == key)
     902          487163 :                 return &values[insertpos];
     903          724431 :             insertpos = (insertpos + 1) & (capacity - 1);
     904                 :         }
     905                 :     }
     906                 : 
     907          520285 :     count++;
     908          520285 :     unsigned newCapacity = HashSetCapacity(count);
     909                 : 
     910          520285 :     if (newCapacity == capacity) {
     911          493267 :         JS_ASSERT(!converting);
     912          493267 :         return &values[insertpos];
     913                 :     }
     914                 : 
     915           27018 :     U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
     916           27018 :     if (!newValues)
     917               0 :         return NULL;
     918           27018 :     PodZero(newValues, newCapacity);
     919                 : 
     920         1542682 :     for (unsigned i = 0; i < capacity; i++) {
     921         1515664 :         if (values[i]) {
     922          784884 :             unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
     923         1720917 :             while (newValues[pos] != NULL)
     924          151149 :                 pos = (pos + 1) & (newCapacity - 1);
     925          784884 :             newValues[pos] = values[i];
     926                 :         }
     927                 :     }
     928                 : 
     929           27018 :     values = newValues;
     930                 : 
     931           27018 :     insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
     932           69989 :     while (values[insertpos] != NULL)
     933           15953 :         insertpos = (insertpos + 1) & (newCapacity - 1);
     934           27018 :     return &values[insertpos];
     935                 : }
     936                 : 
     937                 : /*
     938                 :  * Insert an element into the specified set if it is not already there, returning
     939                 :  * an entry which is NULL if the element was not there.
     940                 :  */
     941                 : template <class T, class U, class KEY>
     942                 : static inline U **
     943        16970315 : HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
     944                 : {
     945        16970315 :     if (count == 0) {
     946          693877 :         JS_ASSERT(values == NULL);
     947          693877 :         count++;
     948          693877 :         return (U **) &values;
     949                 :     }
     950                 : 
     951        16276438 :     if (count == 1) {
     952        10969030 :         U *oldData = (U*) values;
     953        10969030 :         if (KEY::getKey(oldData) == key)
     954        10904536 :             return (U **) &values;
     955                 : 
     956           64494 :         values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
     957           64494 :         if (!values) {
     958               0 :             values = (U **) oldData;
     959               0 :             return NULL;
     960                 :         }
     961           64494 :         PodZero(values, SET_ARRAY_SIZE);
     962           64494 :         count++;
     963                 : 
     964           64494 :         values[0] = oldData;
     965           64494 :         return &values[1];
     966                 :     }
     967                 : 
     968         5307408 :     if (count <= SET_ARRAY_SIZE) {
     969        11957622 :         for (unsigned i = 0; i < count; i++) {
     970        11831796 :             if (KEY::getKey(values[i]) == key)
     971         4184948 :                 return &values[i];
     972                 :         }
     973                 : 
     974          125826 :         if (count < SET_ARRAY_SIZE) {
     975          115012 :             count++;
     976          115012 :             return &values[count - 1];
     977                 :         }
     978                 :     }
     979                 : 
     980         1007448 :     return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
     981                 : }
     982                 : 
     983                 : /* Lookup an entry in a hash set, return NULL if it does not exist. */
     984                 : template <class T, class U, class KEY>
     985                 : static inline U *
     986        48668577 : HashSetLookup(U **values, unsigned count, T key)
     987                 : {
     988        48668577 :     if (count == 0)
     989         7901252 :         return NULL;
     990                 : 
     991        40767325 :     if (count == 1)
     992        33114490 :         return (KEY::getKey((U *) values) == key) ? (U *) values : NULL;
     993                 : 
     994         7652835 :     if (count <= SET_ARRAY_SIZE) {
     995        10998138 :         for (unsigned i = 0; i < count; i++) {
     996        10965497 :             if (KEY::getKey(values[i]) == key)
     997         6556806 :                 return values[i];
     998                 :         }
     999           32641 :         return NULL;
    1000                 :     }
    1001                 : 
    1002         1063388 :     unsigned capacity = HashSetCapacity(count);
    1003         1063388 :     unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
    1004                 : 
    1005         2684437 :     while (values[pos] != NULL) {
    1006         1580709 :         if (KEY::getKey(values[pos]) == key)
    1007         1023048 :             return values[pos];
    1008          557661 :         pos = (pos + 1) & (capacity - 1);
    1009                 :     }
    1010                 : 
    1011           40340 :     return NULL;
    1012                 : }
    1013                 : 
    1014                 : inline bool
    1015       171094302 : TypeSet::hasType(Type type)
    1016                 : {
    1017       171094302 :     if (unknown())
    1018        13604222 :         return true;
    1019                 : 
    1020       157490080 :     if (type.isUnknown()) {
    1021           53095 :         return false;
    1022       157436985 :     } else if (type.isPrimitive()) {
    1023       115909926 :         return !!(flags & PrimitiveTypeFlag(type.primitive()));
    1024        41527059 :     } else if (type.isAnyObject()) {
    1025          351038 :         return !!(flags & TYPE_FLAG_ANYOBJECT);
    1026                 :     } else {
    1027        41176021 :         return !!(flags & TYPE_FLAG_ANYOBJECT) ||
    1028                 :             HashSetLookup<TypeObjectKey*,TypeObjectKey,TypeObjectKey>
    1029        41176021 :             (objectSet, baseObjectCount(), type.objectKey()) != NULL;
    1030                 :     }
    1031                 : }
    1032                 : 
    1033                 : inline void
    1034         1337387 : TypeSet::setBaseObjectCount(uint32_t count)
    1035                 : {
    1036         1337387 :     JS_ASSERT(count <= TYPE_FLAG_OBJECT_COUNT_LIMIT);
    1037                 :     flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
    1038         1337387 :           | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
    1039         1337387 : }
    1040                 : 
    1041                 : inline void
    1042          138771 : TypeSet::clearObjects()
    1043                 : {
    1044          138771 :     setBaseObjectCount(0);
    1045          138771 :     objectSet = NULL;
    1046          138771 : }
    1047                 : 
    1048                 : inline void
    1049         6412854 : TypeSet::addType(JSContext *cx, Type type)
    1050                 : {
    1051         6412854 :     JS_ASSERT(cx->compartment->activeInference);
    1052                 : 
    1053         6412854 :     if (unknown())
    1054         2514689 :         return;
    1055                 : 
    1056         3898165 :     if (type.isUnknown()) {
    1057           71420 :         flags |= TYPE_FLAG_BASE_MASK;
    1058           71420 :         clearObjects();
    1059           71420 :         JS_ASSERT(unknown());
    1060         3826745 :     } else if (type.isPrimitive()) {
    1061         1823934 :         TypeFlags flag = PrimitiveTypeFlag(type.primitive());
    1062         1823934 :         if (flags & flag)
    1063          764293 :             return;
    1064                 : 
    1065                 :         /* If we add float to a type set it is also considered to contain int. */
    1066         1059641 :         if (flag == TYPE_FLAG_DOUBLE)
    1067           49016 :             flag |= TYPE_FLAG_INT32;
    1068                 : 
    1069         1059641 :         flags |= flag;
    1070                 :     } else {
    1071         2002811 :         if (flags & TYPE_FLAG_ANYOBJECT)
    1072            5191 :             return;
    1073         1997620 :         if (type.isAnyObject())
    1074           28267 :             goto unknownObject;
    1075         1969353 :         uint32_t objectCount = baseObjectCount();
    1076         1969353 :         TypeObjectKey *object = type.objectKey();
    1077                 :         TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
    1078         1969353 :                                      (cx->compartment, objectSet, objectCount, object);
    1079         1969353 :         if (!pentry) {
    1080               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    1081               0 :             return;
    1082                 :         }
    1083         1969353 :         if (*pentry)
    1084         1041954 :             return;
    1085          927399 :         *pentry = object;
    1086                 : 
    1087          927399 :         setBaseObjectCount(objectCount);
    1088                 : 
    1089          927399 :         if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT)
    1090              15 :             goto unknownObject;
    1091                 : 
    1092          927384 :         if (type.isTypeObject()) {
    1093          277306 :             TypeObject *nobject = type.typeObject();
    1094          277306 :             JS_ASSERT(!nobject->singleton);
    1095          277306 :             if (nobject->unknownProperties())
    1096           28221 :                 goto unknownObject;
    1097          249085 :             if (objectCount > 1) {
    1098           32350 :                 nobject->contribution += (objectCount - 1) * (objectCount - 1);
    1099           32350 :                 if (nobject->contribution >= TypeObject::CONTRIBUTION_LIMIT) {
    1100                 :                     InferSpew(ISpewOps, "limitUnknown: %sT%p%s",
    1101             422 :                               InferSpewColor(this), this, InferSpewColorReset());
    1102             422 :                     goto unknownObject;
    1103                 :                 }
    1104                 :             }
    1105                 :         }
    1106                 :     }
    1107                 : 
    1108                 :     if (false) {
    1109                 :     unknownObject:
    1110           56925 :         type = Type::AnyObjectType();
    1111           56925 :         flags |= TYPE_FLAG_ANYOBJECT;
    1112           56925 :         clearObjects();
    1113                 :     }
    1114                 : 
    1115                 :     InferSpew(ISpewOps, "addType: %sT%p%s %s",
    1116                 :               InferSpewColor(this), this, InferSpewColorReset(),
    1117         2086727 :               TypeString(type));
    1118                 : 
    1119                 :     /* Propagate the type to all constraints. */
    1120         2086727 :     TypeConstraint *constraint = constraintList;
    1121         5940879 :     while (constraint) {
    1122         1767425 :         cx->compartment->types.addPending(cx, constraint, this, type);
    1123         1767425 :         constraint = constraint->next;
    1124                 :     }
    1125                 : 
    1126         2086727 :     cx->compartment->types.resolvePending(cx);
    1127                 : }
    1128                 : 
    1129                 : inline void
    1130        13999037 : TypeSet::setOwnProperty(JSContext *cx, bool configured)
    1131                 : {
    1132        13999037 :     TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0);
    1133                 : 
    1134        13999037 :     if ((flags & nflags) == nflags)
    1135        13909304 :         return;
    1136                 : 
    1137           89733 :     flags |= nflags;
    1138                 : 
    1139                 :     /* Propagate the change to all constraints. */
    1140           89733 :     TypeConstraint *constraint = constraintList;
    1141          186401 :     while (constraint) {
    1142            6935 :         constraint->newPropertyState(cx, this);
    1143            6935 :         constraint = constraint->next;
    1144                 :     }
    1145                 : }
    1146                 : 
    1147                 : inline unsigned
    1148         6453355 : TypeSet::getObjectCount()
    1149                 : {
    1150         6453355 :     JS_ASSERT(!unknownObject());
    1151         6453355 :     uint32_t count = baseObjectCount();
    1152         6453355 :     if (count > SET_ARRAY_SIZE)
    1153         1949391 :         return HashSetCapacity(count);
    1154         4503964 :     return count;
    1155                 : }
    1156                 : 
    1157                 : inline TypeObjectKey *
    1158         2638378 : TypeSet::getObject(unsigned i)
    1159                 : {
    1160         2638378 :     JS_ASSERT(i < getObjectCount());
    1161         2638378 :     if (baseObjectCount() == 1) {
    1162          860036 :         JS_ASSERT(i == 0);
    1163          860036 :         return (TypeObjectKey *) objectSet;
    1164                 :     }
    1165         1778342 :     return objectSet[i];
    1166                 : }
    1167                 : 
    1168                 : inline JSObject *
    1169          765341 : TypeSet::getSingleObject(unsigned i)
    1170                 : {
    1171          765341 :     TypeObjectKey *key = getObject(i);
    1172          765341 :     return (uintptr_t(key) & 1) ? (JSObject *)(uintptr_t(key) ^ 1) : NULL;
    1173                 : }
    1174                 : 
    1175                 : inline TypeObject *
    1176          840987 : TypeSet::getTypeObject(unsigned i)
    1177                 : {
    1178          840987 :     TypeObjectKey *key = getObject(i);
    1179          840987 :     return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;
    1180                 : }
    1181                 : 
    1182                 : /////////////////////////////////////////////////////////////////////
    1183                 : // TypeCallsite
    1184                 : /////////////////////////////////////////////////////////////////////
    1185                 : 
    1186                 : inline
    1187           57521 : TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
    1188                 :                            bool isNew, unsigned argumentCount)
    1189                 :     : script(script), pc(pc), isNew(isNew), argumentCount(argumentCount),
    1190           57521 :       thisTypes(NULL), returnTypes(NULL)
    1191                 : {
    1192                 :     /* Caller must check for failure. */
    1193           57521 :     argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
    1194           57521 : }
    1195                 : 
    1196                 : /////////////////////////////////////////////////////////////////////
    1197                 : // TypeObject
    1198                 : /////////////////////////////////////////////////////////////////////
    1199                 : 
    1200          346138 : inline TypeObject::TypeObject(JSObject *proto, bool function, bool unknown)
    1201                 : {
    1202          346138 :     PodZero(this);
    1203                 : 
    1204                 :     /* Inner objects may not appear on prototype chains. */
    1205          346138 :     JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
    1206                 : 
    1207          346138 :     this->proto = proto;
    1208                 : 
    1209          346138 :     if (function)
    1210           14025 :         flags |= OBJECT_FLAG_FUNCTION;
    1211          346138 :     if (unknown)
    1212          182901 :         flags |= OBJECT_FLAG_UNKNOWN_MASK;
    1213                 : 
    1214          346138 :     InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
    1215          346138 : }
    1216                 : 
    1217                 : inline uint32_t
    1218        24524934 : TypeObject::basePropertyCount() const
    1219                 : {
    1220        24524934 :     return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
    1221                 : }
    1222                 : 
    1223                 : inline void
    1224          358522 : TypeObject::setBasePropertyCount(uint32_t count)
    1225                 : {
    1226          358522 :     JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
    1227                 :     flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
    1228          358522 :           | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
    1229          358522 : }
    1230                 : 
    1231                 : inline TypeSet *
    1232        14686877 : TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
    1233                 : {
    1234        14686877 :     JS_ASSERT(cx->compartment->activeInference);
    1235        14686877 :     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
    1236        14686877 :     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
    1237        14686877 :     JS_ASSERT(!unknownProperties());
    1238                 : 
    1239        14686877 :     uint32_t propertyCount = basePropertyCount();
    1240                 :     Property **pprop = HashSetInsert<jsid,Property,Property>
    1241        14686877 :                            (cx->compartment, propertySet, propertyCount, id);
    1242        14686877 :     if (!pprop) {
    1243               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    1244               0 :         return NULL;
    1245                 :     }
    1246                 : 
    1247        14686877 :     if (!*pprop) {
    1248          152184 :         setBasePropertyCount(propertyCount);
    1249          152184 :         if (!addProperty(cx, id, pprop))
    1250               0 :             return NULL;
    1251          152184 :         if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
    1252               0 :             markUnknown(cx);
    1253               0 :             TypeSet *types = TypeSet::make(cx, "propertyOverflow");
    1254               0 :             types->addType(cx, Type::UnknownType());
    1255               0 :             return types;
    1256                 :         }
    1257                 :     }
    1258                 : 
    1259        14686877 :     TypeSet *types = &(*pprop)->types;
    1260                 : 
    1261        14686877 :     if (assign)
    1262        13667350 :         types->setOwnProperty(cx, false);
    1263                 : 
    1264        14686877 :     return types;
    1265                 : }
    1266                 : 
    1267                 : inline TypeSet *
    1268         8421831 : TypeObject::maybeGetProperty(JSContext *cx, jsid id)
    1269                 : {
    1270         8421831 :     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
    1271         8421831 :     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id));
    1272         8421831 :     JS_ASSERT(!unknownProperties());
    1273                 : 
    1274                 :     Property *prop = HashSetLookup<jsid,Property,Property>
    1275         8421831 :         (propertySet, basePropertyCount(), id);
    1276                 : 
    1277         8421831 :     return prop ? &prop->types : NULL;
    1278                 : }
    1279                 : 
    1280                 : inline unsigned
    1281          452774 : TypeObject::getPropertyCount()
    1282                 : {
    1283          452774 :     uint32_t count = basePropertyCount();
    1284          452774 :     if (count > SET_ARRAY_SIZE)
    1285            1316 :         return HashSetCapacity(count);
    1286          451458 :     return count;
    1287                 : }
    1288                 : 
    1289                 : inline Property *
    1290           15947 : TypeObject::getProperty(unsigned i)
    1291                 : {
    1292           15947 :     JS_ASSERT(i < getPropertyCount());
    1293           15947 :     if (basePropertyCount() == 1) {
    1294            4016 :         JS_ASSERT(i == 0);
    1295            4016 :         return (Property *) propertySet;
    1296                 :     }
    1297           11931 :     return propertySet[i];
    1298                 : }
    1299                 : 
    1300                 : inline void
    1301          246841 : TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
    1302                 : {
    1303          246841 :     TypeObjectFlags flags = 0;
    1304                 : 
    1305          246841 :     switch (key) {
    1306                 :       case JSProto_Function:
    1307           14025 :         JS_ASSERT(isFunction());
    1308                 :         /* FALLTHROUGH */
    1309                 : 
    1310                 :       case JSProto_Object:
    1311                 :         flags = OBJECT_FLAG_NON_DENSE_ARRAY
    1312                 :               | OBJECT_FLAG_NON_PACKED_ARRAY
    1313          237595 :               | OBJECT_FLAG_NON_TYPED_ARRAY;
    1314          237595 :         break;
    1315                 : 
    1316                 :       case JSProto_Array:
    1317            8289 :         flags = OBJECT_FLAG_NON_TYPED_ARRAY;
    1318            8289 :         break;
    1319                 : 
    1320                 :       default:
    1321                 :         /* :XXX: abstract */
    1322               0 :         JS_ASSERT(key == JSProto_Int8Array ||
    1323                 :                   key == JSProto_Uint8Array ||
    1324                 :                   key == JSProto_Int16Array ||
    1325                 :                   key == JSProto_Uint16Array ||
    1326                 :                   key == JSProto_Int32Array ||
    1327                 :                   key == JSProto_Uint32Array ||
    1328                 :                   key == JSProto_Float32Array ||
    1329                 :                   key == JSProto_Float64Array ||
    1330             957 :                   key == JSProto_Uint8ClampedArray);
    1331                 :         flags = OBJECT_FLAG_NON_DENSE_ARRAY
    1332             957 :               | OBJECT_FLAG_NON_PACKED_ARRAY;
    1333             957 :         break;
    1334                 :     }
    1335                 : 
    1336          246841 :     if (!hasAllFlags(flags))
    1337          150087 :         setFlags(cx, flags);
    1338          246841 : }
    1339                 : 
    1340                 : inline JSObject *
    1341               0 : TypeObject::getGlobal()
    1342                 : {
    1343               0 :     if (singleton)
    1344               0 :         return &singleton->global();
    1345               0 :     if (interpretedFunction && interpretedFunction->script()->compileAndGo)
    1346               0 :         return &interpretedFunction->global();
    1347               0 :     return NULL;
    1348                 : }
    1349                 : 
    1350                 : inline void
    1351        10645876 : TypeObject::writeBarrierPre(TypeObject *type)
    1352                 : {
    1353                 : #ifdef JSGC_INCREMENTAL
    1354        10645876 :     if (!type)
    1355         1692685 :         return;
    1356                 : 
    1357         8953191 :     JSCompartment *comp = type->compartment();
    1358         8953191 :     if (comp->needsBarrier()) {
    1359            1146 :         TypeObject *tmp = type;
    1360            1146 :         MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
    1361            1146 :         JS_ASSERT(tmp == type);
    1362                 :     }
    1363                 : #endif
    1364                 : }
    1365                 : 
    1366                 : inline void
    1367        15734705 : TypeObject::writeBarrierPost(TypeObject *type, void *addr)
    1368                 : {
    1369        15734705 : }
    1370                 : 
    1371                 : inline void
    1372        41838774 : TypeObject::readBarrier(TypeObject *type)
    1373                 : {
    1374                 : #ifdef JSGC_INCREMENTAL
    1375        41838774 :     JSCompartment *comp = type->compartment();
    1376        41838774 :     if (comp->needsBarrier()) {
    1377            5754 :         TypeObject *tmp = type;
    1378            5754 :         MarkTypeObjectUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
    1379            5754 :         JS_ASSERT(tmp == type);
    1380                 :     }
    1381                 : #endif
    1382        41838774 : }
    1383                 : 
    1384                 : inline void
    1385             619 : TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
    1386                 : {
    1387                 : #ifdef JSGC_INCREMENTAL
    1388             619 :     if (!newScript)
    1389             579 :         return;
    1390                 : 
    1391              40 :     JSCompartment *comp = newScript->fun->compartment();
    1392              40 :     if (comp->needsBarrier()) {
    1393               0 :         MarkObject(comp->barrierTracer(), &newScript->fun, "write barrier");
    1394               0 :         MarkShape(comp->barrierTracer(), &newScript->shape, "write barrier");
    1395                 :     }
    1396                 : #endif
    1397                 : }
    1398                 : 
    1399                 : inline void
    1400             619 : TypeNewScript::writeBarrierPost(TypeNewScript *newScript, void *addr)
    1401                 : {
    1402             619 : }
    1403                 : 
    1404                 : inline
    1405          152184 : Property::Property(jsid id)
    1406          152184 :   : id(id)
    1407                 : {
    1408          152184 : }
    1409                 : 
    1410                 : inline
    1411           21534 : Property::Property(const Property &o)
    1412           21534 :   : id(o.id.get()), types(o.types)
    1413                 : {
    1414           21534 : }
    1415                 : 
    1416                 : } } /* namespace js::types */
    1417                 : 
    1418                 : inline bool
    1419       102566654 : JSScript::ensureHasTypes(JSContext *cx)
    1420                 : {
    1421       102566654 :     return types || makeTypes(cx);
    1422                 : }
    1423                 : 
    1424                 : inline bool
    1425       102493944 : JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
    1426                 : {
    1427       102493944 :     JSScript *self = this;
    1428                 : 
    1429       102493944 :     if (!self->ensureHasTypes(cx))
    1430               0 :         return false;
    1431       102493944 :     if (!self->types->hasScope()) {
    1432          307890 :         js::CheckRoot root(cx, &self);
    1433          307890 :         js::RootObject objRoot(cx, &scope);
    1434          153945 :         if (!js::types::TypeScript::SetScope(cx, self, scope))
    1435               0 :             return false;
    1436                 :     }
    1437       102493944 :     if (!self->hasAnalysis() && !self->makeAnalysis(cx))
    1438               0 :         return false;
    1439       102493944 :     JS_ASSERT(self->analysis()->ranBytecode());
    1440       102493944 :     return true;
    1441                 : }
    1442                 : 
    1443                 : inline bool
    1444         4355484 : JSScript::ensureRanInference(JSContext *cx)
    1445                 : {
    1446         4355484 :     if (!ensureRanAnalysis(cx, NULL))
    1447               0 :         return false;
    1448         4355484 :     if (!analysis()->ranInference()) {
    1449           77188 :         js::types::AutoEnterTypeInference enter(cx);
    1450           38594 :         analysis()->analyzeTypes(cx);
    1451                 :     }
    1452         4355484 :     return !analysis()->OOM() &&
    1453         4355484 :         !cx->compartment->types.pendingNukeTypes;
    1454                 : }
    1455                 : 
    1456                 : inline bool
    1457      2028248078 : JSScript::hasAnalysis()
    1458                 : {
    1459      2028248078 :     return types && types->analysis;
    1460                 : }
    1461                 : 
    1462                 : inline js::analyze::ScriptAnalysis *
    1463      1062778766 : JSScript::analysis()
    1464                 : {
    1465      1062778766 :     JS_ASSERT(hasAnalysis());
    1466      1062778766 :     return types->analysis;
    1467                 : }
    1468                 : 
    1469                 : inline void
    1470          428422 : JSScript::clearAnalysis()
    1471                 : {
    1472          428422 :     if (types)
    1473          218213 :         types->analysis = NULL;
    1474          428422 : }
    1475                 : 
    1476                 : inline void
    1477                 : js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
    1478                 :                                            js::types::Type type)
    1479                 : {
    1480                 :     js::types::TypeSet *pushed = pushedTypes(offset, which);
    1481                 :     pushed->addType(cx, type);
    1482                 : }
    1483                 : 
    1484                 : inline js::types::TypeObject *
    1485         1336772 : JSCompartment::getEmptyType(JSContext *cx)
    1486                 : {
    1487         1336772 :     if (!emptyTypeObject)
    1488           22524 :         emptyTypeObject = types.newTypeObject(cx, NULL, JSProto_Object, NULL, true);
    1489         1336772 :     return emptyTypeObject;
    1490                 : }
    1491                 : 
    1492                 : #endif // jsinferinlines_h___

Generated by: LCOV version 1.7