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

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