LCOV - code coverage report
Current view: directory - js/src - jsinfer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2818 2335 82.9 %
Date: 2012-06-02 Functions: 197 184 93.4 %

       1                 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
       2                 : /* vim: set ts=40 sw=4 et tw=99: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is the Mozilla SpiderMonkey bytecode type inference
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  *   Mozilla Foundation
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Brian Hackett <bhackett@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "jsapi.h"
      41                 : #include "jsautooplen.h"
      42                 : #include "jsbool.h"
      43                 : #include "jsdate.h"
      44                 : #include "jsexn.h"
      45                 : #include "jsfriendapi.h"
      46                 : #include "jsgc.h"
      47                 : #include "jsgcmark.h"
      48                 : #include "jsinfer.h"
      49                 : #include "jsmath.h"
      50                 : #include "jsnum.h"
      51                 : #include "jsobj.h"
      52                 : #include "jsscript.h"
      53                 : #include "jscntxt.h"
      54                 : #include "jsscope.h"
      55                 : #include "jsstr.h"
      56                 : #include "jsiter.h"
      57                 : 
      58                 : #include "frontend/TokenStream.h"
      59                 : #include "js/MemoryMetrics.h"
      60                 : #include "methodjit/MethodJIT.h"
      61                 : #include "methodjit/Retcon.h"
      62                 : #ifdef JS_METHODJIT
      63                 : # include "assembler/assembler/MacroAssembler.h"
      64                 : #endif
      65                 : 
      66                 : #include "jsatominlines.h"
      67                 : #include "jsgcinlines.h"
      68                 : #include "jsinferinlines.h"
      69                 : #include "jsobjinlines.h"
      70                 : #include "jsscriptinlines.h"
      71                 : #include "vm/Stack-inl.h"
      72                 : 
      73                 : #ifdef JS_HAS_XML_SUPPORT
      74                 : #include "jsxml.h"
      75                 : #endif
      76                 : 
      77                 : #ifdef __SUNPRO_CC
      78                 : #include <alloca.h>
      79                 : #endif
      80                 : 
      81                 : using namespace js;
      82                 : using namespace js::types;
      83                 : using namespace js::analyze;
      84                 : 
      85                 : static inline jsid
      86           30459 : id_prototype(JSContext *cx) {
      87           30459 :     return ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
      88                 : }
      89                 : 
      90                 : static inline jsid
      91                 : id_arguments(JSContext *cx) {
      92                 :     return ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
      93                 : }
      94                 : 
      95                 : static inline jsid
      96             335 : id_length(JSContext *cx) {
      97             335 :     return ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
      98                 : }
      99                 : 
     100                 : static inline jsid
     101          965821 : id___proto__(JSContext *cx) {
     102          965821 :     return ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
     103                 : }
     104                 : 
     105                 : static inline jsid
     106          960901 : id_constructor(JSContext *cx) {
     107          960901 :     return ATOM_TO_JSID(cx->runtime->atomState.constructorAtom);
     108                 : }
     109                 : 
     110                 : static inline jsid
     111          959849 : id_caller(JSContext *cx) {
     112          959849 :     return ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
     113                 : }
     114                 : 
     115                 : static inline jsid
     116                 : id_toString(JSContext *cx)
     117                 : {
     118                 :     return ATOM_TO_JSID(cx->runtime->atomState.toStringAtom);
     119                 : }
     120                 : 
     121                 : static inline jsid
     122                 : id_toSource(JSContext *cx)
     123                 : {
     124                 :     return ATOM_TO_JSID(cx->runtime->atomState.toSourceAtom);
     125                 : }
     126                 : 
     127                 : #ifdef DEBUG
     128                 : const char *
     129          188589 : types::TypeIdStringImpl(jsid id)
     130                 : {
     131          188589 :     if (JSID_IS_VOID(id))
     132           21248 :         return "(index)";
     133          167341 :     if (JSID_IS_EMPTY(id))
     134           15381 :         return "(new)";
     135                 :     static char bufs[4][100];
     136                 :     static unsigned which = 0;
     137          151960 :     which = (which + 1) & 3;
     138          151960 :     PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0);
     139          151960 :     return bufs[which];
     140                 : }
     141                 : #endif
     142                 : 
     143                 : /////////////////////////////////////////////////////////////////////
     144                 : // Logging
     145                 : /////////////////////////////////////////////////////////////////////
     146                 : 
     147        24653260 : static bool InferSpewActive(SpewChannel channel)
     148                 : {
     149                 :     static bool active[SPEW_COUNT];
     150                 :     static bool checked = false;
     151        24653260 :     if (!checked) {
     152           19811 :         checked = true;
     153           19811 :         PodArrayZero(active);
     154           19811 :         const char *env = getenv("INFERFLAGS");
     155           19811 :         if (!env)
     156           19811 :             return false;
     157               0 :         if (strstr(env, "ops"))
     158               0 :             active[ISpewOps] = true;
     159               0 :         if (strstr(env, "result"))
     160               0 :             active[ISpewResult] = true;
     161               0 :         if (strstr(env, "full")) {
     162               0 :             for (unsigned i = 0; i < SPEW_COUNT; i++)
     163               0 :                 active[i] = true;
     164                 :         }
     165                 :     }
     166        24633449 :     return active[channel];
     167                 : }
     168                 : 
     169                 : #ifdef DEBUG
     170                 : 
     171        42986572 : static bool InferSpewColorable()
     172                 : {
     173                 :     /* Only spew colors on xterm-color to not screw up emacs. */
     174        42986572 :     const char *env = getenv("TERM");
     175        42986572 :     if (!env)
     176               0 :         return false;
     177        42986572 :     return strcmp(env, "xterm-color") == 0;
     178                 : }
     179                 : 
     180                 : const char *
     181        21493286 : types::InferSpewColorReset()
     182                 : {
     183        21493286 :     if (!InferSpewColorable())
     184        21493286 :         return "";
     185               0 :     return "\x1b[0m";
     186                 : }
     187                 : 
     188                 : const char *
     189        10852331 : types::InferSpewColor(TypeConstraint *constraint)
     190                 : {
     191                 :     /* Type constraints are printed out using foreground colors. */
     192                 :     static const char *colors[] = { "\x1b[31m", "\x1b[32m", "\x1b[33m",
     193                 :                                     "\x1b[34m", "\x1b[35m", "\x1b[36m",
     194                 :                                     "\x1b[37m" };
     195        10852331 :     if (!InferSpewColorable())
     196        10852331 :         return "";
     197               0 :     return colors[DefaultHasher<TypeConstraint *>::hash(constraint) % 7];
     198                 : }
     199                 : 
     200                 : const char *
     201        10640955 : types::InferSpewColor(TypeSet *types)
     202                 : {
     203                 :     /* Type sets are printed out using bold colors. */
     204                 :     static const char *colors[] = { "\x1b[1;31m", "\x1b[1;32m", "\x1b[1;33m",
     205                 :                                     "\x1b[1;34m", "\x1b[1;35m", "\x1b[1;36m",
     206                 :                                     "\x1b[1;37m" };
     207        10640955 :     if (!InferSpewColorable())
     208        10640955 :         return "";
     209               0 :     return colors[DefaultHasher<TypeSet *>::hash(types) % 7];
     210                 : }
     211                 : 
     212                 : const char *
     213        14551553 : types::TypeString(Type type)
     214                 : {
     215        14551553 :     if (type.isPrimitive()) {
     216         7122100 :         switch (type.primitive()) {
     217                 :           case JSVAL_TYPE_UNDEFINED:
     218         3997971 :             return "void";
     219                 :           case JSVAL_TYPE_NULL:
     220           66775 :             return "null";
     221                 :           case JSVAL_TYPE_BOOLEAN:
     222          128938 :             return "bool";
     223                 :           case JSVAL_TYPE_INT32:
     224         2226242 :             return "int";
     225                 :           case JSVAL_TYPE_DOUBLE:
     226          240321 :             return "float";
     227                 :           case JSVAL_TYPE_STRING:
     228          453028 :             return "string";
     229                 :           case JSVAL_TYPE_MAGIC:
     230            8825 :             return "lazyargs";
     231                 :           default:
     232               0 :             JS_NOT_REACHED("Bad type");
     233                 :             return "";
     234                 :         }
     235                 :     }
     236         7429453 :     if (type.isUnknown())
     237          154967 :         return "unknown";
     238         7274486 :     if (type.isAnyObject())
     239          242842 :         return " object";
     240                 : 
     241                 :     static char bufs[4][40];
     242                 :     static unsigned which = 0;
     243         7031644 :     which = (which + 1) & 3;
     244                 : 
     245         7031644 :     if (type.isSingleObject())
     246         3292070 :         JS_snprintf(bufs[which], 40, "<0x%p>", (void *) type.singleObject());
     247                 :     else
     248         3739574 :         JS_snprintf(bufs[which], 40, "[0x%p]", (void *) type.typeObject());
     249                 : 
     250         7031644 :     return bufs[which];
     251                 : }
     252                 : 
     253                 : const char *
     254         1026621 : types::TypeObjectString(TypeObject *type)
     255                 : {
     256         1026621 :     return TypeString(Type::ObjectType(type));
     257                 : }
     258                 : 
     259        10636139 : unsigned JSScript::id() {
     260        10636139 :     if (!id_) {
     261           84985 :         id_ = ++compartment()->types.scriptCount;
     262                 :         InferSpew(ISpewOps, "script #%u: %p %s:%d",
     263           84985 :                   id_, this, filename ? filename : "<null>", lineno);
     264                 :     }
     265        10636139 :     return id_;
     266                 : }
     267                 : 
     268                 : void
     269        24611319 : types::InferSpew(SpewChannel channel, const char *fmt, ...)
     270                 : {
     271        24611319 :     if (!InferSpewActive(channel))
     272        24611319 :         return;
     273                 : 
     274                 :     va_list ap;
     275               0 :     va_start(ap, fmt);
     276               0 :     fprintf(stdout, "[infer] ");
     277               0 :     vfprintf(stdout, fmt, ap);
     278               0 :     fprintf(stdout, "\n");
     279               0 :     va_end(ap);
     280                 : }
     281                 : 
     282                 : bool
     283        41577119 : types::TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value)
     284                 : {
     285                 :     /*
     286                 :      * Check the correctness of the type information in the object's property
     287                 :      * against an actual value.
     288                 :      */
     289        41577119 :     if (cx->typeInferenceEnabled() && !obj->unknownProperties() && !value.isUndefined()) {
     290          959849 :         id = MakeTypeId(cx, id);
     291                 : 
     292                 :         /* Watch for properties which inference does not monitor. */
     293          959849 :         if (id == id___proto__(cx) || id == id_constructor(cx) || id == id_caller(cx))
     294               0 :             return true;
     295                 : 
     296                 :         /*
     297                 :          * If we called in here while resolving a type constraint, we may be in the
     298                 :          * middle of resolving a standard class and the type sets will not be updated
     299                 :          * until the outer TypeSet::add finishes.
     300                 :          */
     301          959849 :         if (cx->compartment->types.pendingCount)
     302               0 :             return true;
     303                 : 
     304          959849 :         Type type = GetValueType(cx, value);
     305                 : 
     306         1919698 :         AutoEnterTypeInference enter(cx);
     307                 : 
     308                 :         /*
     309                 :          * We don't track types for properties inherited from prototypes which
     310                 :          * haven't yet been accessed during analysis of the inheriting object.
     311                 :          * Don't do the property instantiation now.
     312                 :          */
     313          959849 :         TypeSet *types = obj->maybeGetProperty(cx, id);
     314          959849 :         if (!types)
     315               0 :             return true;
     316                 : 
     317                 :         /*
     318                 :          * If the types inherited from prototypes are not being propagated into
     319                 :          * this set (because we haven't analyzed code which accesses the
     320                 :          * property), skip.
     321                 :          */
     322          959849 :         if (!types->hasPropagatedProperty())
     323          812763 :             return true;
     324                 : 
     325          147086 :         if (!types->hasType(type)) {
     326                 :             TypeFailure(cx, "Missing type in object %s %s: %s",
     327               0 :                         TypeObjectString(obj), TypeIdString(id), TypeString(type));
     328                 :         }
     329                 :     }
     330        40764356 :     return true;
     331                 : }
     332                 : 
     333                 : #endif
     334                 : 
     335                 : void
     336               0 : types::TypeFailure(JSContext *cx, const char *fmt, ...)
     337                 : {
     338                 :     char msgbuf[1024]; /* Larger error messages will be truncated */
     339                 :     char errbuf[1024];
     340                 : 
     341                 :     va_list ap;
     342               0 :     va_start(ap, fmt);
     343               0 :     JS_vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
     344               0 :     va_end(ap);
     345                 : 
     346               0 :     JS_snprintf(msgbuf, sizeof(msgbuf), "[infer failure] %s", errbuf);
     347                 : 
     348                 :     /* Dump type state, even if INFERFLAGS is unset. */
     349               0 :     cx->compartment->types.print(cx, true);
     350                 : 
     351                 :     /* Always active, even in release builds */
     352               0 :     MOZ_Assert(msgbuf, __FILE__, __LINE__);
     353                 :     
     354               0 :     *((volatile int *)NULL) = 0;  /* Should never be reached */
     355               0 : }
     356                 : 
     357                 : /////////////////////////////////////////////////////////////////////
     358                 : // TypeSet
     359                 : /////////////////////////////////////////////////////////////////////
     360                 : 
     361                 : TypeSet *
     362            1194 : TypeSet::make(JSContext *cx, const char *name)
     363                 : {
     364            1194 :     JS_ASSERT(cx->compartment->activeInference);
     365                 : 
     366            1194 :     TypeSet *res = cx->typeLifoAlloc().new_<TypeSet>();
     367            1194 :     if (!res) {
     368               0 :         cx->compartment->types.setPendingNukeTypes(cx);
     369               0 :         return NULL;
     370                 :     }
     371                 : 
     372                 :     InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
     373                 :               InferSpewColor(res), res, InferSpewColorReset(),
     374            1194 :               name);
     375                 : 
     376            1194 :     return res;
     377                 : }
     378                 : 
     379                 : inline void
     380         4604451 : TypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
     381                 : {
     382         4604451 :     if (!constraint) {
     383                 :         /* OOM failure while constructing the constraint. */
     384               0 :         cx->compartment->types.setPendingNukeTypes(cx);
     385               0 :         return;
     386                 :     }
     387                 : 
     388         4604451 :     JS_ASSERT(cx->compartment->activeInference);
     389                 : 
     390                 :     InferSpew(ISpewOps, "addConstraint: %sT%p%s %sC%p%s %s",
     391                 :               InferSpewColor(this), this, InferSpewColorReset(),
     392                 :               InferSpewColor(constraint), constraint, InferSpewColorReset(),
     393         4604451 :               constraint->kind());
     394                 : 
     395         4604451 :     JS_ASSERT(constraint->next == NULL);
     396         4604451 :     constraint->next = constraintList;
     397         4604451 :     constraintList = constraint;
     398                 : 
     399         4604451 :     if (!callExisting)
     400         2053380 :         return;
     401                 : 
     402                 :     /* If any type is possible, there's no need to worry about specifics. */
     403         2551071 :     if (flags & TYPE_FLAG_UNKNOWN) {
     404           22943 :         cx->compartment->types.addPending(cx, constraint, this, Type::UnknownType());
     405                 :     } else {
     406                 :         /* Enqueue type set members stored as bits. */ 
     407        20225024 :         for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
     408        17696896 :             if (flags & flag) {
     409          774277 :                 Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
     410          774277 :                 cx->compartment->types.addPending(cx, constraint, this, type);
     411                 :             }
     412                 :         }
     413                 : 
     414                 :         /* If any object is possible, skip specifics. */
     415         2528128 :         if (flags & TYPE_FLAG_ANYOBJECT) {
     416           11289 :             cx->compartment->types.addPending(cx, constraint, this, Type::AnyObjectType());
     417                 :         } else {
     418                 :             /* Enqueue specific object types. */
     419         2516839 :             unsigned count = getObjectCount();
     420         3536983 :             for (unsigned i = 0; i < count; i++) {
     421         1020144 :                 TypeObjectKey *object = getObject(i);
     422         1020144 :                 if (object)
     423                 :                     cx->compartment->types.addPending(cx, constraint, this,
     424          567207 :                                                       Type::ObjectType(object));
     425                 :             }
     426                 :         }
     427                 :     }
     428                 : 
     429         2551071 :     cx->compartment->types.resolvePending(cx);
     430                 : }
     431                 : 
     432                 : void
     433               0 : TypeSet::print(JSContext *cx)
     434                 : {
     435               0 :     if (flags & TYPE_FLAG_OWN_PROPERTY)
     436               0 :         printf(" [own]");
     437               0 :     if (flags & TYPE_FLAG_CONFIGURED_PROPERTY)
     438               0 :         printf(" [configured]");
     439                 : 
     440               0 :     if (isDefiniteProperty())
     441               0 :         printf(" [definite:%d]", definiteSlot());
     442                 : 
     443               0 :     if (baseFlags() == 0 && !baseObjectCount()) {
     444               0 :         printf(" missing");
     445               0 :         return;
     446                 :     }
     447                 : 
     448               0 :     if (flags & TYPE_FLAG_UNKNOWN)
     449               0 :         printf(" unknown");
     450               0 :     if (flags & TYPE_FLAG_ANYOBJECT)
     451               0 :         printf(" object");
     452                 : 
     453               0 :     if (flags & TYPE_FLAG_UNDEFINED)
     454               0 :         printf(" void");
     455               0 :     if (flags & TYPE_FLAG_NULL)
     456               0 :         printf(" null");
     457               0 :     if (flags & TYPE_FLAG_BOOLEAN)
     458               0 :         printf(" bool");
     459               0 :     if (flags & TYPE_FLAG_INT32)
     460               0 :         printf(" int");
     461               0 :     if (flags & TYPE_FLAG_DOUBLE)
     462               0 :         printf(" float");
     463               0 :     if (flags & TYPE_FLAG_STRING)
     464               0 :         printf(" string");
     465               0 :     if (flags & TYPE_FLAG_LAZYARGS)
     466               0 :         printf(" lazyargs");
     467                 : 
     468               0 :     uint32_t objectCount = baseObjectCount();
     469               0 :     if (objectCount) {
     470               0 :         printf(" object[%u]", objectCount);
     471                 : 
     472               0 :         unsigned count = getObjectCount();
     473               0 :         for (unsigned i = 0; i < count; i++) {
     474               0 :             TypeObjectKey *object = getObject(i);
     475               0 :             if (object)
     476               0 :                 printf(" %s", TypeString(Type::ObjectType(object)));
     477                 :         }
     478                 :     }
     479                 : }
     480                 : 
     481                 : bool
     482              38 : TypeSet::propertyNeedsBarrier(JSContext *cx, jsid id)
     483                 : {
     484              38 :     id = MakeTypeId(cx, id);
     485                 : 
     486              38 :     if (unknownObject())
     487              24 :         return true;
     488                 : 
     489              14 :     for (unsigned i = 0; i < getObjectCount(); i++) {
     490               6 :         if (getSingleObject(i))
     491               0 :             return true;
     492                 : 
     493               6 :         if (types::TypeObject *otype = getTypeObject(i)) {
     494               6 :             if (otype->unknownProperties())
     495               0 :                 return true;
     496                 : 
     497               6 :             if (types::TypeSet *propTypes = otype->maybeGetProperty(cx, id)) {
     498               6 :                 if (propTypes->needsBarrier(cx))
     499               6 :                     return true;
     500                 :             }
     501                 :         }
     502                 :     }
     503                 : 
     504               8 :     addFreeze(cx);
     505               8 :     return false;
     506                 : }
     507                 : 
     508                 : /////////////////////////////////////////////////////////////////////
     509                 : // TypeSet constraints
     510                 : /////////////////////////////////////////////////////////////////////
     511                 : 
     512                 : /* Standard subset constraint, propagate all types from one set to another. */
     513                 : class TypeConstraintSubset : public TypeConstraint
     514                 : {
     515                 : public:
     516                 :     TypeSet *target;
     517                 : 
     518         1071923 :     TypeConstraintSubset(TypeSet *target)
     519         1071923 :         : TypeConstraint("subset"), target(target)
     520                 :     {
     521         1071923 :         JS_ASSERT(target);
     522         1071923 :     }
     523                 : 
     524         1019994 :     void newType(JSContext *cx, TypeSet *source, Type type)
     525                 :     {
     526                 :         /* Basic subset constraint, move all types to the target. */
     527         1019994 :         target->addType(cx, type);
     528         1019994 :     }
     529                 : };
     530                 : 
     531                 : void
     532         1071923 : TypeSet::addSubset(JSContext *cx, TypeSet *target)
     533                 : {
     534         1071923 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
     535         1071923 : }
     536                 : 
     537                 : /* Constraints for reads/writes on object properties. */
     538                 : class TypeConstraintProp : public TypeConstraint
     539                 : {
     540                 : public:
     541                 :     JSScript *script;
     542                 :     jsbytecode *pc;
     543                 : 
     544                 :     /*
     545                 :      * If assign is true, the target is used to update a property of the object.
     546                 :      * If assign is false, the target is assigned the value of the property.
     547                 :      */
     548                 :     bool assign;
     549                 :     TypeSet *target;
     550                 : 
     551                 :     /* Property being accessed. */
     552                 :     jsid id;
     553                 : 
     554           54587 :     TypeConstraintProp(JSScript *script, jsbytecode *pc,
     555                 :                        TypeSet *target, jsid id, bool assign)
     556                 :         : TypeConstraint("prop"), script(script), pc(pc),
     557           54587 :           assign(assign), target(target), id(id)
     558                 :     {
     559           54587 :         JS_ASSERT(script && pc && target);
     560           54587 :     }
     561                 : 
     562                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     563                 : };
     564                 : 
     565                 : void
     566           43626 : TypeSet::addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
     567                 :                         TypeSet *target, jsid id)
     568                 : {
     569           43626 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintProp>(script, pc, target, id, false));
     570           43626 : }
     571                 : 
     572                 : void
     573           10961 : TypeSet::addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
     574                 :                         TypeSet *target, jsid id)
     575                 : {
     576           10961 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintProp>(script, pc, target, id, true));
     577           10961 : }
     578                 : 
     579                 : /*
     580                 :  * Constraints for updating the 'this' types of callees on CALLPROP/CALLELEM.
     581                 :  * These are derived from the types on the properties themselves, rather than
     582                 :  * those pushed in the 'this' slot at the call site, which allows us to retain
     583                 :  * correlations between the type of the 'this' object and the associated
     584                 :  * callee scripts at polymorphic call sites.
     585                 :  */
     586                 : class TypeConstraintCallProp : public TypeConstraint
     587                 : {
     588                 : public:
     589                 :     JSScript *script;
     590                 :     jsbytecode *callpc;
     591                 : 
     592                 :     /* Property being accessed. */
     593                 :     jsid id;
     594                 : 
     595           16023 :     TypeConstraintCallProp(JSScript *script, jsbytecode *callpc, jsid id)
     596           16023 :         : TypeConstraint("callprop"), script(script), callpc(callpc), id(id)
     597                 :     {
     598           16023 :         JS_ASSERT(script && callpc);
     599           16023 :     }
     600                 : 
     601                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     602                 : };
     603                 : 
     604                 : void
     605           16023 : TypeSet::addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id)
     606                 : {
     607                 :     /*
     608                 :      * For calls which will go through JSOP_NEW, don't add any constraints to
     609                 :      * modify the 'this' types of callees. The initial 'this' value will be
     610                 :      * outright ignored.
     611                 :      */
     612           16023 :     jsbytecode *callpc = script->analysis()->getCallPC(pc);
     613           16023 :     if (JSOp(*callpc) == JSOP_NEW)
     614               0 :         return;
     615                 : 
     616           16023 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintCallProp>(script, callpc, id));
     617                 : }
     618                 : 
     619                 : /*
     620                 :  * Constraints for generating 'set' property constraints on a SETELEM only if
     621                 :  * the element type may be a number. For SETELEM we only account for integer
     622                 :  * indexes, and if the element cannot be an integer (e.g. it must be a string)
     623                 :  * then we lose precision by treating it like one.
     624                 :  */
     625                 : class TypeConstraintSetElement : public TypeConstraint
     626                 : {
     627                 : public:
     628                 :     JSScript *script;
     629                 :     jsbytecode *pc;
     630                 : 
     631                 :     TypeSet *objectTypes;
     632                 :     TypeSet *valueTypes;
     633                 : 
     634            4338 :     TypeConstraintSetElement(JSScript *script, jsbytecode *pc,
     635                 :                              TypeSet *objectTypes, TypeSet *valueTypes)
     636                 :         : TypeConstraint("setelement"), script(script), pc(pc),
     637            4338 :           objectTypes(objectTypes), valueTypes(valueTypes)
     638                 :     {
     639            4338 :         JS_ASSERT(script && pc);
     640            4338 :     }
     641                 : 
     642                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     643                 : };
     644                 : 
     645                 : void
     646            4338 : TypeSet::addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
     647                 :                        TypeSet *objectTypes, TypeSet *valueTypes)
     648                 : {
     649            4338 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintSetElement>(script, pc, objectTypes,
     650            4338 :                                                                valueTypes));
     651            4338 : }
     652                 : 
     653                 : /*
     654                 :  * Constraints for watching call edges as they are discovered and invoking native
     655                 :  * function handlers, adding constraints for arguments, receiver objects and the
     656                 :  * return value, and updating script foundOffsets.
     657                 :  */
     658                 : class TypeConstraintCall : public TypeConstraint
     659                 : {
     660                 : public:
     661                 :     /* Call site being tracked. */
     662                 :     TypeCallsite *callsite;
     663                 : 
     664           56863 :     TypeConstraintCall(TypeCallsite *callsite)
     665           56863 :         : TypeConstraint("call"), callsite(callsite)
     666           56863 :     {}
     667                 : 
     668                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     669                 : };
     670                 : 
     671                 : void
     672           56863 : TypeSet::addCall(JSContext *cx, TypeCallsite *site)
     673                 : {
     674           56863 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintCall>(site));
     675           56863 : }
     676                 : 
     677                 : /* Constraints for arithmetic operations. */
     678                 : class TypeConstraintArith : public TypeConstraint
     679                 : {
     680                 : public:
     681                 :     JSScript *script;
     682                 :     jsbytecode *pc;
     683                 : 
     684                 :     /* Type set receiving the result of the arithmetic. */
     685                 :     TypeSet *target;
     686                 : 
     687                 :     /* For addition operations, the other operand. */
     688                 :     TypeSet *other;
     689                 : 
     690          700369 :     TypeConstraintArith(JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
     691          700369 :         : TypeConstraint("arith"), script(script), pc(pc), target(target), other(other)
     692                 :     {
     693          700369 :         JS_ASSERT(target);
     694          700369 :     }
     695                 : 
     696                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     697                 : };
     698                 : 
     699                 : void
     700          700369 : TypeSet::addArith(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
     701                 : {
     702          700369 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(script, pc, target, other));
     703          700369 : }
     704                 : 
     705                 : /* Subset constraint which transforms primitive values into appropriate objects. */
     706                 : class TypeConstraintTransformThis : public TypeConstraint
     707                 : {
     708                 : public:
     709                 :     JSScript *script;
     710                 :     TypeSet *target;
     711                 : 
     712           13069 :     TypeConstraintTransformThis(JSScript *script, TypeSet *target)
     713           13069 :         : TypeConstraint("transformthis"), script(script), target(target)
     714           13069 :     {}
     715                 : 
     716                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     717                 : };
     718                 : 
     719                 : void
     720           13069 : TypeSet::addTransformThis(JSContext *cx, JSScript *script, TypeSet *target)
     721                 : {
     722           13069 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintTransformThis>(script, target));
     723           13069 : }
     724                 : 
     725                 : /*
     726                 :  * Constraint which adds a particular type to the 'this' types of all
     727                 :  * discovered scripted functions.
     728                 :  */
     729                 : class TypeConstraintPropagateThis : public TypeConstraint
     730                 : {
     731                 : public:
     732                 :     JSScript *script;
     733                 :     jsbytecode *callpc;
     734                 :     Type type;
     735                 :     TypeSet *types;
     736                 : 
     737           46841 :     TypeConstraintPropagateThis(JSScript *script, jsbytecode *callpc, Type type, TypeSet *types)
     738           46841 :         : TypeConstraint("propagatethis"), script(script), callpc(callpc), type(type), types(types)
     739           46841 :     {}
     740                 : 
     741                 :     void newType(JSContext *cx, TypeSet *source, Type type);
     742                 : };
     743                 : 
     744                 : void
     745           31087 : TypeSet::addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type type, TypeSet *types)
     746                 : {
     747                 :     /* Don't add constraints when the call will be 'new' (see addCallProperty). */
     748           31087 :     jsbytecode *callpc = script->analysis()->getCallPC(pc);
     749           31087 :     if (JSOp(*callpc) == JSOP_NEW)
     750               0 :         return;
     751                 : 
     752           31087 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
     753                 : }
     754                 : 
     755                 : /* Subset constraint which filters out primitive types. */
     756                 : class TypeConstraintFilterPrimitive : public TypeConstraint
     757                 : {
     758                 : public:
     759                 :     TypeSet *target;
     760                 :     TypeSet::FilterKind filter;
     761                 : 
     762            4689 :     TypeConstraintFilterPrimitive(TypeSet *target, TypeSet::FilterKind filter)
     763            4689 :         : TypeConstraint("filter"), target(target), filter(filter)
     764            4689 :     {}
     765                 : 
     766            4701 :     void newType(JSContext *cx, TypeSet *source, Type type)
     767                 :     {
     768            4701 :         switch (filter) {
     769                 :           case TypeSet::FILTER_ALL_PRIMITIVES:
     770            4701 :             if (type.isPrimitive())
     771            4693 :                 return;
     772               8 :             break;
     773                 : 
     774                 :           case TypeSet::FILTER_NULL_VOID:
     775               0 :             if (type.isPrimitive(JSVAL_TYPE_NULL) || type.isPrimitive(JSVAL_TYPE_UNDEFINED))
     776               0 :                 return;
     777               0 :             break;
     778                 : 
     779                 :           case TypeSet::FILTER_VOID:
     780               0 :             if (type.isPrimitive(JSVAL_TYPE_UNDEFINED))
     781               0 :                 return;
     782               0 :             break;
     783                 : 
     784                 :           default:
     785               0 :             JS_NOT_REACHED("Bad filter");
     786                 :         }
     787                 : 
     788               8 :         target->addType(cx, type);
     789                 :     }
     790                 : };
     791                 : 
     792                 : void
     793            4689 : TypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter)
     794                 : {
     795            4689 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFilterPrimitive>(target, filter));
     796            4689 : }
     797                 : 
     798                 : /* If id is a normal slotful 'own' property of an object, get its shape. */
     799                 : static inline const Shape *
     800          423470 : GetSingletonShape(JSContext *cx, JSObject *obj, jsid id)
     801                 : {
     802          423470 :     const Shape *shape = obj->nativeLookup(cx, id);
     803          423470 :     if (shape && shape->hasDefaultGetterOrIsMethod() && shape->hasSlot())
     804          414202 :         return shape;
     805            9268 :     return NULL;
     806                 : }
     807                 : 
     808                 : void
     809          324625 : ScriptAnalysis::pruneTypeBarriers(JSContext *cx, uint32_t offset)
     810                 : {
     811          324625 :     TypeBarrier **pbarrier = &getCode(offset).typeBarriers;
     812         1186076 :     while (*pbarrier) {
     813          536826 :         TypeBarrier *barrier = *pbarrier;
     814          536826 :         if (barrier->target->hasType(barrier->type)) {
     815                 :             /* Barrier is now obsolete, it can be removed. */
     816           45108 :             *pbarrier = barrier->next;
     817           45108 :             continue;
     818                 :         }
     819          491718 :         if (barrier->singleton) {
     820           17973 :             JS_ASSERT(barrier->type.isPrimitive(JSVAL_TYPE_UNDEFINED));
     821           17973 :             const Shape *shape = GetSingletonShape(cx, barrier->singleton, barrier->singletonId);
     822           17973 :             if (shape && !barrier->singleton->nativeGetSlot(shape->slot()).isUndefined()) {
     823                 :                 /*
     824                 :                  * When we analyzed the script the singleton had an 'own'
     825                 :                  * property which was undefined (probably a 'var' variable
     826                 :                  * added to a global object), but now it is defined. The only
     827                 :                  * way it can become undefined again is if an explicit assign
     828                 :                  * or deletion on the property occurs, which will update the
     829                 :                  * type set for the property directly and trigger construction
     830                 :                  * of a normal type barrier.
     831                 :                  */
     832            4966 :                 *pbarrier = barrier->next;
     833            4966 :                 continue;
     834                 :             }
     835                 :         }
     836          486752 :         pbarrier = &barrier->next;
     837                 :     }
     838          324625 : }
     839                 : 
     840                 : /*
     841                 :  * Cheesy limit on the number of objects we will tolerate in an observed type
     842                 :  * set before refusing to add new type barriers for objects.
     843                 :  * :FIXME: this heuristic sucks, and doesn't handle calls.
     844                 :  */
     845                 : static const uint32_t BARRIER_OBJECT_LIMIT = 10;
     846                 : 
     847           27851 : void ScriptAnalysis::breakTypeBarriers(JSContext *cx, uint32_t offset, bool all)
     848                 : {
     849           27851 :     pruneTypeBarriers(cx, offset);
     850                 : 
     851           27851 :     bool resetResolving = !cx->compartment->types.resolving;
     852           27851 :     if (resetResolving)
     853           27851 :         cx->compartment->types.resolving = true;
     854                 : 
     855           27851 :     TypeBarrier **pbarrier = &getCode(offset).typeBarriers;
     856           86061 :     while (*pbarrier) {
     857           30359 :         TypeBarrier *barrier = *pbarrier;
     858           30359 :         if (barrier->target->hasType(barrier->type) ) {
     859                 :             /*
     860                 :              * Barrier is now obsolete, it can be removed. This is not
     861                 :              * redundant with the pruneTypeBarriers() call above, as breaking
     862                 :              * previous type barriers may have modified the target type set.
     863                 :              */
     864               0 :             *pbarrier = barrier->next;
     865           30359 :         } else if (all) {
     866                 :             /* Force removal of the barrier. */
     867             124 :             barrier->target->addType(cx, barrier->type);
     868             124 :             *pbarrier = barrier->next;
     869           93211 :         } else if (!barrier->type.isUnknown() &&
     870           24416 :                    !barrier->type.isAnyObject() &&
     871           23204 :                    barrier->type.isObject() &&
     872           15356 :                    barrier->target->getObjectCount() >= BARRIER_OBJECT_LIMIT) {
     873                 :             /* Maximum number of objects in the set exceeded. */
     874              16 :             barrier->target->addType(cx, barrier->type);
     875              16 :             *pbarrier = barrier->next;
     876                 :         } else {
     877           30219 :             pbarrier = &barrier->next;
     878                 :         }
     879                 :     }
     880                 : 
     881           27851 :     if (resetResolving) {
     882           27851 :         cx->compartment->types.resolving = false;
     883           27851 :         cx->compartment->types.resolvePending(cx);
     884                 :     }
     885           27851 : }
     886                 : 
     887              79 : void ScriptAnalysis::breakTypeBarriersSSA(JSContext *cx, const SSAValue &v)
     888                 : {
     889              79 :     if (v.kind() != SSAValue::PUSHED)
     890               0 :         return;
     891                 : 
     892              79 :     uint32_t offset = v.pushedOffset();
     893              79 :     if (JSOp(script->code[offset]) == JSOP_GETPROP)
     894              32 :         breakTypeBarriersSSA(cx, poppedValue(offset, 0));
     895                 : 
     896              79 :     breakTypeBarriers(cx, offset, true);
     897                 : }
     898                 : 
     899                 : /*
     900                 :  * Subset constraint for property reads and argument passing which can add type
     901                 :  * barriers on the read instead of passing types along.
     902                 :  */
     903                 : class TypeConstraintSubsetBarrier : public TypeConstraint
     904                 : {
     905                 : public:
     906                 :     JSScript *script;
     907                 :     jsbytecode *pc;
     908                 :     TypeSet *target;
     909                 : 
     910          485074 :     TypeConstraintSubsetBarrier(JSScript *script, jsbytecode *pc, TypeSet *target)
     911          485074 :         : TypeConstraint("subsetBarrier"), script(script), pc(pc), target(target)
     912          485074 :     {}
     913                 : 
     914          666334 :     void newType(JSContext *cx, TypeSet *source, Type type)
     915                 :     {
     916          666334 :         if (!target->hasType(type))
     917          522765 :             script->analysis()->addTypeBarrier(cx, pc, target, type);
     918          666334 :     }
     919                 : };
     920                 : 
     921                 : void
     922          485074 : TypeSet::addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
     923                 : {
     924          485074 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubsetBarrier>(script, pc, target));
     925          485074 : }
     926                 : 
     927                 : /*
     928                 :  * Constraint which marks a pushed ARGUMENTS value as unknown if the script has
     929                 :  * an arguments object created in the future.
     930                 :  */
     931                 : class TypeConstraintLazyArguments : public TypeConstraint
     932                 : {
     933                 : public:
     934                 :     TypeSet *target;
     935                 : 
     936            1758 :     TypeConstraintLazyArguments(TypeSet *target)
     937            1758 :         : TypeConstraint("lazyArgs"), target(target)
     938            1758 :     {}
     939                 : 
     940               0 :     void newType(JSContext *cx, TypeSet *source, Type type) {}
     941                 : 
     942            6302 :     void newObjectState(JSContext *cx, TypeObject *object, bool force)
     943                 :     {
     944            6302 :         if (object->hasAnyFlags(OBJECT_FLAG_CREATED_ARGUMENTS))
     945            3610 :             target->addType(cx, Type::UnknownType());
     946            6302 :     }
     947                 : };
     948                 : 
     949                 : void
     950            1758 : TypeSet::addLazyArguments(JSContext *cx, TypeSet *target)
     951                 : {
     952            1758 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintLazyArguments>(target));
     953            1758 : }
     954                 : 
     955                 : /////////////////////////////////////////////////////////////////////
     956                 : // TypeConstraint
     957                 : /////////////////////////////////////////////////////////////////////
     958                 : 
     959                 : /* Get the object to use for a property access on type. */
     960                 : static inline TypeObject *
     961           77964 : GetPropertyObject(JSContext *cx, JSScript *script, Type type)
     962                 : {
     963           77964 :     if (type.isTypeObject())
     964           52016 :         return type.typeObject();
     965                 : 
     966                 :     /* Force instantiation of lazy types for singleton objects. */
     967           25948 :     if (type.isSingleObject())
     968           13209 :         return type.singleObject()->getType(cx);
     969                 : 
     970                 :     /*
     971                 :      * Handle properties attached to primitive types, treating this access as a
     972                 :      * read on the primitive's new object.
     973                 :      */
     974           12739 :     TypeObject *object = NULL;
     975           12739 :     switch (type.primitive()) {
     976                 : 
     977                 :       case JSVAL_TYPE_INT32:
     978                 :       case JSVAL_TYPE_DOUBLE:
     979             355 :         object = TypeScript::StandardType(cx, script, JSProto_Number);
     980             355 :         break;
     981                 : 
     982                 :       case JSVAL_TYPE_BOOLEAN:
     983              74 :         object = TypeScript::StandardType(cx, script, JSProto_Boolean);
     984              74 :         break;
     985                 : 
     986                 :       case JSVAL_TYPE_STRING:
     987            6209 :         object = TypeScript::StandardType(cx, script, JSProto_String);
     988            6209 :         break;
     989                 : 
     990                 :       default:
     991                 :         /* undefined, null and lazy arguments do not have properties. */
     992            6101 :         return NULL;
     993                 :     }
     994                 : 
     995            6638 :     if (!object)
     996               0 :         cx->compartment->types.setPendingNukeTypes(cx);
     997            6638 :     return object;
     998                 : }
     999                 : 
    1000                 : static inline bool
    1001          450181 : UsePropertyTypeBarrier(jsbytecode *pc)
    1002                 : {
    1003                 :     /*
    1004                 :      * At call opcodes, type barriers can only be added for the call bindings,
    1005                 :      * which TypeConstraintCall will add barrier constraints for directly.
    1006                 :      */
    1007          450181 :     uint32_t format = js_CodeSpec[*pc].format;
    1008          450181 :     return (format & JOF_TYPESET) && !(format & JOF_INVOKE);
    1009                 : }
    1010                 : 
    1011                 : static inline void
    1012            7155 : MarkPropertyAccessUnknown(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
    1013                 : {
    1014            7155 :     if (UsePropertyTypeBarrier(pc))
    1015            7144 :         script->analysis()->addTypeBarrier(cx, pc, target, Type::UnknownType());
    1016                 :     else
    1017              11 :         target->addType(cx, Type::UnknownType());
    1018            7155 : }
    1019                 : 
    1020                 : /*
    1021                 :  * Handle a property access on a specific object. All property accesses go through
    1022                 :  * here, whether via x.f, x[f], or global name accesses.
    1023                 :  */
    1024                 : static inline void
    1025          483492 : PropertyAccess(JSContext *cx, JSScript *script, jsbytecode *pc, TypeObject *object,
    1026                 :                bool assign, TypeSet *target, jsid id)
    1027                 : {
    1028                 :     /* Reads from objects with unknown properties are unknown, writes to such objects are ignored. */
    1029          483492 :     if (object->unknownProperties()) {
    1030              35 :         if (!assign)
    1031              17 :             MarkPropertyAccessUnknown(cx, script, pc, target);
    1032              35 :         return;
    1033                 :     }
    1034                 : 
    1035                 :     /* Capture the effects of a standard property access. */
    1036          483457 :     TypeSet *types = object->getProperty(cx, id, assign);
    1037          483457 :     if (!types)
    1038               0 :         return;
    1039          483457 :     if (assign) {
    1040           40431 :         target->addSubset(cx, types);
    1041                 :     } else {
    1042          443026 :         if (!types->hasPropagatedProperty())
    1043           43398 :             object->getFromPrototypes(cx, id, types);
    1044          443026 :         if (UsePropertyTypeBarrier(pc)) {
    1045          442929 :             types->addSubsetBarrier(cx, script, pc, target);
    1046          442929 :             if (object->singleton && !JSID_IS_VOID(id)) {
    1047                 :                 /*
    1048                 :                  * Add a singleton type barrier on the object if it has an
    1049                 :                  * 'own' property which is currently undefined. We'll be able
    1050                 :                  * to remove the barrier after the property becomes defined,
    1051                 :                  * even if no undefined value is ever observed at pc.
    1052                 :                  */
    1053          405497 :                 const Shape *shape = GetSingletonShape(cx, object->singleton, id);
    1054          405497 :                 if (shape && object->singleton->nativeGetSlot(shape->slot()).isUndefined())
    1055           13080 :                     script->analysis()->addSingletonTypeBarrier(cx, pc, target, object->singleton, id);
    1056                 :             }
    1057                 :         } else {
    1058              97 :             types->addSubset(cx, target);
    1059                 :         }
    1060                 :     }
    1061                 : }
    1062                 : 
    1063                 : /* Whether the JSObject/TypeObject referent of an access on type cannot be determined. */
    1064                 : static inline bool
    1065           88586 : UnknownPropertyAccess(JSScript *script, Type type)
    1066                 : {
    1067           88586 :     return type.isUnknown()
    1068           87288 :         || type.isAnyObject()
    1069          175874 :         || (!type.isObject() && !script->hasGlobal());
    1070                 : }
    1071                 : 
    1072                 : void
    1073           70103 : TypeConstraintProp::newType(JSContext *cx, TypeSet *source, Type type)
    1074                 : {
    1075           70103 :     if (UnknownPropertyAccess(script, type)) {
    1076                 :         /*
    1077                 :          * Access on an unknown object. Reads produce an unknown result, writes
    1078                 :          * need to be monitored.
    1079                 :          */
    1080            7858 :         if (assign)
    1081            1059 :             cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
    1082                 :         else
    1083            6799 :             MarkPropertyAccessUnknown(cx, script, pc, target);
    1084            7858 :         return;
    1085                 :     }
    1086                 : 
    1087           62245 :     if (type.isPrimitive(JSVAL_TYPE_MAGIC)) {
    1088                 :         /* Ignore cases which will be accounted for by the followEscapingArguments analysis. */
    1089             851 :         if (assign || (id != JSID_VOID && id != id_length(cx)))
    1090             207 :             return;
    1091                 : 
    1092             644 :         if (id == JSID_VOID)
    1093             339 :             MarkPropertyAccessUnknown(cx, script, pc, target);
    1094                 :         else
    1095             305 :             target->addType(cx, Type::Int32Type());
    1096             644 :         return;
    1097                 :     }
    1098                 : 
    1099           61394 :     TypeObject *object = GetPropertyObject(cx, script, type);
    1100           61394 :     if (object)
    1101           56107 :         PropertyAccess(cx, script, pc, object, assign, target, id);
    1102                 : }
    1103                 : 
    1104                 : void
    1105           18483 : TypeConstraintCallProp::newType(JSContext *cx, TypeSet *source, Type type)
    1106                 : {
    1107                 :     /*
    1108                 :      * For CALLPROP, we need to update not just the pushed types but also the
    1109                 :      * 'this' types of possible callees. If we can't figure out that set of
    1110                 :      * callees, monitor the call to make sure discovered callees get their
    1111                 :      * 'this' types updated.
    1112                 :      */
    1113                 : 
    1114           18483 :     if (UnknownPropertyAccess(script, type)) {
    1115            1913 :         cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
    1116            1913 :         return;
    1117                 :     }
    1118                 : 
    1119           16570 :     TypeObject *object = GetPropertyObject(cx, script, type);
    1120           16570 :     if (object) {
    1121           15756 :         if (object->unknownProperties()) {
    1122               2 :             cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
    1123                 :         } else {
    1124           15754 :             TypeSet *types = object->getProperty(cx, id, false);
    1125           15754 :             if (!types)
    1126               0 :                 return;
    1127           15754 :             if (!types->hasPropagatedProperty())
    1128               0 :                 object->getFromPrototypes(cx, id, types);
    1129                 :             /* Bypass addPropagateThis, we already have the callpc. */
    1130           15754 :             types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
    1131           31508 :                             script, callpc, type, (TypeSet *) NULL));
    1132                 :         }
    1133                 :     }
    1134                 : }
    1135                 : 
    1136                 : void
    1137            5199 : TypeConstraintSetElement::newType(JSContext *cx, TypeSet *source, Type type)
    1138                 : {
    1139           11913 :     if (type.isUnknown() ||
    1140            5163 :         type.isPrimitive(JSVAL_TYPE_INT32) ||
    1141            1551 :         type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
    1142            3661 :         objectTypes->addSetProperty(cx, script, pc, valueTypes, JSID_VOID);
    1143                 :     }
    1144            5199 : }
    1145                 : 
    1146                 : void
    1147           62687 : TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type)
    1148                 : {
    1149           62687 :     JSScript *script = callsite->script;
    1150           62687 :     jsbytecode *pc = callsite->pc;
    1151                 : 
    1152           62687 :     if (type.isUnknown() || type.isAnyObject()) {
    1153                 :         /* Monitor calls on unknown functions. */
    1154            2038 :         cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
    1155            2038 :         return;
    1156                 :     }
    1157                 : 
    1158           60649 :     JSFunction *callee = NULL;
    1159                 : 
    1160           60649 :     if (type.isSingleObject()) {
    1161           55576 :         JSObject *obj = type.singleObject();
    1162                 : 
    1163           55576 :         if (!obj->isFunction()) {
    1164                 :             /* Calls on non-functions are dynamically monitored. */
    1165               6 :             return;
    1166                 :         }
    1167                 : 
    1168           55570 :         if (obj->toFunction()->isNative()) {
    1169                 :             /*
    1170                 :              * The return value and all side effects within native calls should
    1171                 :              * be dynamically monitored, except when the compiler is generating
    1172                 :              * specialized inline code or stub calls for a specific natives and
    1173                 :              * knows about the behavior of that native.
    1174                 :              */
    1175           31279 :             cx->compartment->types.monitorBytecode(cx, script, pc - script->code, true);
    1176                 : 
    1177                 :             /*
    1178                 :              * Add type constraints capturing the possible behavior of
    1179                 :              * specialized natives which operate on properties. :XXX: use
    1180                 :              * better factoring for both this and the compiler code itself
    1181                 :              * which specializes particular natives.
    1182                 :              */
    1183                 : 
    1184           31279 :             Native native = obj->toFunction()->native();
    1185                 : 
    1186           31279 :             if (native == js::array_push) {
    1187            3506 :                 for (size_t i = 0; i < callsite->argumentCount; i++) {
    1188                 :                     callsite->thisTypes->addSetProperty(cx, script, pc,
    1189            1754 :                                                         callsite->argumentTypes[i], JSID_VOID);
    1190                 :                 }
    1191                 :             }
    1192                 : 
    1193           31279 :             if (native == js::array_pop || native == js::array_shift)
    1194             110 :                 callsite->thisTypes->addGetProperty(cx, script, pc, callsite->returnTypes, JSID_VOID);
    1195                 : 
    1196           31279 :             if (native == js_Array) {
    1197             421 :                 TypeObject *res = TypeScript::InitObject(cx, script, pc, JSProto_Array);
    1198             421 :                 if (!res)
    1199               0 :                     return;
    1200                 : 
    1201             421 :                 callsite->returnTypes->addType(cx, Type::ObjectType(res));
    1202                 : 
    1203             421 :                 if (callsite->argumentCount >= 2) {
    1204             190 :                     for (unsigned i = 0; i < callsite->argumentCount; i++) {
    1205                 :                         PropertyAccess(cx, script, pc, res, true,
    1206             148 :                                        callsite->argumentTypes[i], JSID_VOID);
    1207                 :                     }
    1208                 :                 }
    1209                 :             }
    1210                 : 
    1211           31279 :             return;
    1212                 :         }
    1213                 : 
    1214           24291 :         callee = obj->toFunction();
    1215            5073 :     } else if (type.isTypeObject()) {
    1216            3973 :         callee = type.typeObject()->interpretedFunction;
    1217            3973 :         if (!callee)
    1218              30 :             return;
    1219                 :     } else {
    1220                 :         /* Calls on non-objects are dynamically monitored. */
    1221            1100 :         return;
    1222                 :     }
    1223                 : 
    1224           28234 :     if (!callee->script()->ensureHasTypes(cx))
    1225               0 :         return;
    1226                 : 
    1227           28234 :     unsigned nargs = callee->nargs;
    1228                 : 
    1229                 :     /* Add bindings for the arguments of the call. */
    1230           64967 :     for (unsigned i = 0; i < callsite->argumentCount && i < nargs; i++) {
    1231           36733 :         TypeSet *argTypes = callsite->argumentTypes[i];
    1232           36733 :         TypeSet *types = TypeScript::ArgTypes(callee->script(), i);
    1233           36733 :         argTypes->addSubsetBarrier(cx, script, pc, types);
    1234                 :     }
    1235                 : 
    1236                 :     /* Add void type for any formals in the callee not supplied at the call site. */
    1237           62642 :     for (unsigned i = callsite->argumentCount; i < nargs; i++) {
    1238           34408 :         TypeSet *types = TypeScript::ArgTypes(callee->script(), i);
    1239           34408 :         types->addType(cx, Type::UndefinedType());
    1240                 :     }
    1241                 : 
    1242           28234 :     TypeSet *thisTypes = TypeScript::ThisTypes(callee->script());
    1243           28234 :     TypeSet *returnTypes = TypeScript::ReturnTypes(callee->script());
    1244                 : 
    1245           28234 :     if (callsite->isNew) {
    1246                 :         /*
    1247                 :          * If the script does not return a value then the pushed value is the
    1248                 :          * new object (typical case). Note that we don't model construction of
    1249                 :          * the new value, which is done dynamically; we don't keep track of the
    1250                 :          * possible 'new' types for a given prototype type object.
    1251                 :          */
    1252            4689 :         thisTypes->addSubset(cx, callsite->returnTypes);
    1253                 :         returnTypes->addFilterPrimitives(cx, callsite->returnTypes,
    1254            4689 :                                          TypeSet::FILTER_ALL_PRIMITIVES);
    1255                 :     } else {
    1256                 :         /*
    1257                 :          * Add a binding for the return value of the call. We don't add a
    1258                 :          * binding for the receiver object, as this is done with PropagateThis
    1259                 :          * constraints added by the original JSOP_CALL* op. The type sets we
    1260                 :          * manipulate here have lost any correlations between particular types
    1261                 :          * in the 'this' and 'callee' sets, which we want to maintain for
    1262                 :          * polymorphic JSOP_CALLPROP invocations.
    1263                 :          */
    1264           23545 :         returnTypes->addSubset(cx, callsite->returnTypes);
    1265                 :     }
    1266                 : }
    1267                 : 
    1268                 : void
    1269           53405 : TypeConstraintPropagateThis::newType(JSContext *cx, TypeSet *source, Type type)
    1270                 : {
    1271           53405 :     if (type.isUnknown() || type.isAnyObject()) {
    1272                 :         /*
    1273                 :          * The callee is unknown, make sure the call is monitored so we pick up
    1274                 :          * possible this/callee correlations. This only comes into play for
    1275                 :          * CALLPROP, for other calls we are past the type barrier and a
    1276                 :          * TypeConstraintCall will also monitor the call.
    1277                 :          */
    1278             315 :         cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
    1279             315 :         return;
    1280                 :     }
    1281                 : 
    1282                 :     /* Ignore calls to natives, these will be handled by TypeConstraintCall. */
    1283           53090 :     JSFunction *callee = NULL;
    1284                 : 
    1285           53090 :     if (type.isSingleObject()) {
    1286           49601 :         JSObject *object = type.singleObject();
    1287           49601 :         if (!object->isFunction() || !object->toFunction()->isInterpreted())
    1288           29861 :             return;
    1289           19740 :         callee = object->toFunction();
    1290            3489 :     } else if (type.isTypeObject()) {
    1291            2459 :         TypeObject *object = type.typeObject();
    1292            2459 :         if (!object->interpretedFunction)
    1293              14 :             return;
    1294            2445 :         callee = object->interpretedFunction;
    1295                 :     } else {
    1296                 :         /* Ignore calls to primitives, these will go through a stub. */
    1297            1030 :         return;
    1298                 :     }
    1299                 : 
    1300           22185 :     if (!callee->script()->ensureHasTypes(cx))
    1301               0 :         return;
    1302                 : 
    1303           22185 :     TypeSet *thisTypes = TypeScript::ThisTypes(callee->script());
    1304           22185 :     if (this->types)
    1305             149 :         this->types->addSubset(cx, thisTypes);
    1306                 :     else
    1307           22036 :         thisTypes->addType(cx, this->type);
    1308                 : }
    1309                 : 
    1310                 : void
    1311           52683 : TypeConstraintArith::newType(JSContext *cx, TypeSet *source, Type type)
    1312                 : {
    1313                 :     /*
    1314                 :      * We only model a subset of the arithmetic behavior that is actually
    1315                 :      * possible. The following need to be watched for at runtime:
    1316                 :      *
    1317                 :      * 1. Operations producing a double where no operand was a double.
    1318                 :      * 2. Operations producing a string where no operand was a string (addition only).
    1319                 :      * 3. Operations producing a value other than int/double/string.
    1320                 :      */
    1321           52683 :     if (other) {
    1322                 :         /*
    1323                 :          * Addition operation, consider these cases:
    1324                 :          *   {int,bool} x {int,bool} -> int
    1325                 :          *   double x {int,bool,double} -> double
    1326                 :          *   string x any -> string
    1327                 :          */
    1328           28933 :         if (type.isUnknown() || other->unknown()) {
    1329             965 :             target->addType(cx, Type::UnknownType());
    1330           27968 :         } else if (type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
    1331            1320 :             if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
    1332                 :                                   TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_BOOLEAN |
    1333            1320 :                                   TYPE_FLAG_ANYOBJECT)) {
    1334            1083 :                 target->addType(cx, Type::DoubleType());
    1335             237 :             } else if (other->getObjectCount() != 0) {
    1336               0 :                 TypeDynamicResult(cx, script, pc, Type::DoubleType());
    1337                 :             }
    1338           26648 :         } else if (type.isPrimitive(JSVAL_TYPE_STRING)) {
    1339            9027 :             target->addType(cx, Type::StringType());
    1340           17621 :         } else if (other->hasAnyFlag(TYPE_FLAG_DOUBLE)) {
    1341             504 :             target->addType(cx, Type::DoubleType());
    1342           17117 :         } else if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
    1343                 :                                      TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN |
    1344           17117 :                                      TYPE_FLAG_ANYOBJECT)) {
    1345           10337 :             target->addType(cx, Type::Int32Type());
    1346            6780 :         } else if (other->getObjectCount() != 0) {
    1347              27 :             TypeDynamicResult(cx, script, pc, Type::Int32Type());
    1348                 :         }
    1349                 :     } else {
    1350           23750 :         if (type.isUnknown())
    1351             107 :             target->addType(cx, Type::UnknownType());
    1352           23643 :         else if (type.isPrimitive(JSVAL_TYPE_DOUBLE))
    1353            3517 :             target->addType(cx, Type::DoubleType());
    1354           20126 :         else if (!type.isAnyObject() && type.isObject())
    1355             221 :             TypeDynamicResult(cx, script, pc, Type::Int32Type());
    1356                 :         else
    1357           19905 :             target->addType(cx, Type::Int32Type());
    1358                 :     }
    1359           52683 : }
    1360                 : 
    1361                 : void
    1362           14178 : TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, Type type)
    1363                 : {
    1364           14178 :     if (type.isUnknown() || type.isAnyObject() || type.isObject() || script->strictModeCode) {
    1365           13945 :         target->addType(cx, type);
    1366           13945 :         return;
    1367                 :     }
    1368                 : 
    1369                 :     /*
    1370                 :      * Note: if |this| is null or undefined, the pushed value is the outer window. We
    1371                 :      * can't use script->getGlobalType() here because it refers to the inner window.
    1372                 :      */
    1373             641 :     if (!script->hasGlobal() ||
    1374             205 :         type.isPrimitive(JSVAL_TYPE_NULL) ||
    1375             203 :         type.isPrimitive(JSVAL_TYPE_UNDEFINED)) {
    1376             205 :         target->addType(cx, Type::UnknownType());
    1377             205 :         return;
    1378                 :     }
    1379                 : 
    1380              28 :     TypeObject *object = NULL;
    1381              28 :     switch (type.primitive()) {
    1382                 :       case JSVAL_TYPE_INT32:
    1383                 :       case JSVAL_TYPE_DOUBLE:
    1384               4 :         object = TypeScript::StandardType(cx, script, JSProto_Number);
    1385               4 :         break;
    1386                 :       case JSVAL_TYPE_BOOLEAN:
    1387               2 :         object = TypeScript::StandardType(cx, script, JSProto_Boolean);
    1388               2 :         break;
    1389                 :       case JSVAL_TYPE_STRING:
    1390              22 :         object = TypeScript::StandardType(cx, script, JSProto_String);
    1391              22 :         break;
    1392                 :       default:
    1393               0 :         return;
    1394                 :     }
    1395                 : 
    1396              28 :     if (!object) {
    1397               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    1398               0 :         return;
    1399                 :     }
    1400                 : 
    1401              28 :     target->addType(cx, Type::ObjectType(object));
    1402                 : }
    1403                 : 
    1404                 : /////////////////////////////////////////////////////////////////////
    1405                 : // Freeze constraints
    1406                 : /////////////////////////////////////////////////////////////////////
    1407                 : 
    1408                 : /* Constraint which triggers recompilation of a script if any type is added to a type set. */
    1409                 : class TypeConstraintFreeze : public TypeConstraint
    1410                 : {
    1411                 : public:
    1412                 :     RecompileInfo info;
    1413                 : 
    1414                 :     /* Whether a new type has already been added, triggering recompilation. */
    1415                 :     bool typeAdded;
    1416                 : 
    1417          419711 :     TypeConstraintFreeze(RecompileInfo info)
    1418          419711 :         : TypeConstraint("freeze"), info(info), typeAdded(false)
    1419          419711 :     {}
    1420                 : 
    1421          224498 :     void newType(JSContext *cx, TypeSet *source, Type type)
    1422                 :     {
    1423          224498 :         if (typeAdded)
    1424          111559 :             return;
    1425                 : 
    1426          112939 :         typeAdded = true;
    1427          112939 :         cx->compartment->types.addPendingRecompile(cx, info);
    1428                 :     }
    1429                 : };
    1430                 : 
    1431                 : void
    1432          331726 : TypeSet::addFreeze(JSContext *cx)
    1433                 : {
    1434          331726 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreeze>(
    1435          663452 :                 cx->compartment->types.compiledInfo), false);
    1436          331726 : }
    1437                 : 
    1438                 : /*
    1439                 :  * Constraint which triggers recompilation of a script if a possible new JSValueType
    1440                 :  * tag is realized for a type set.
    1441                 :  */
    1442                 : class TypeConstraintFreezeTypeTag : public TypeConstraint
    1443                 : {
    1444                 : public:
    1445                 :     RecompileInfo info;
    1446                 : 
    1447                 :     /*
    1448                 :      * Whether the type tag has been marked unknown due to a type change which
    1449                 :      * occurred after this constraint was generated (and which triggered recompilation).
    1450                 :      */
    1451                 :     bool typeUnknown;
    1452                 : 
    1453         1218130 :     TypeConstraintFreezeTypeTag(RecompileInfo info)
    1454         1218130 :         : TypeConstraint("freezeTypeTag"), info(info), typeUnknown(false)
    1455         1218130 :     {}
    1456                 : 
    1457          754950 :     void newType(JSContext *cx, TypeSet *source, Type type)
    1458                 :     {
    1459          754950 :         if (typeUnknown)
    1460           55373 :             return;
    1461                 : 
    1462          699577 :         if (!type.isUnknown() && !type.isAnyObject() && type.isObject()) {
    1463                 :             /* Ignore new objects when the type set already has other objects. */
    1464          508125 :             if (source->getObjectCount() >= 2)
    1465          320000 :                 return;
    1466                 :         }
    1467                 : 
    1468          379577 :         typeUnknown = true;
    1469          379577 :         cx->compartment->types.addPendingRecompile(cx, info);
    1470                 :     }
    1471                 : };
    1472                 : 
    1473                 : static inline JSValueType
    1474         1051125 : GetValueTypeFromTypeFlags(TypeFlags flags)
    1475                 : {
    1476         1051125 :     switch (flags) {
    1477                 :       case TYPE_FLAG_UNDEFINED:
    1478           89313 :         return JSVAL_TYPE_UNDEFINED;
    1479                 :       case TYPE_FLAG_NULL:
    1480            9362 :         return JSVAL_TYPE_NULL;
    1481                 :       case TYPE_FLAG_BOOLEAN:
    1482            9443 :         return JSVAL_TYPE_BOOLEAN;
    1483                 :       case TYPE_FLAG_INT32:
    1484          331626 :         return JSVAL_TYPE_INT32;
    1485                 :       case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE):
    1486           34702 :         return JSVAL_TYPE_DOUBLE;
    1487                 :       case TYPE_FLAG_STRING:
    1488           85160 :         return JSVAL_TYPE_STRING;
    1489                 :       case TYPE_FLAG_LAZYARGS:
    1490             247 :         return JSVAL_TYPE_MAGIC;
    1491                 :       case TYPE_FLAG_ANYOBJECT:
    1492           25103 :         return JSVAL_TYPE_OBJECT;
    1493                 :       default:
    1494          466169 :         return JSVAL_TYPE_UNKNOWN;
    1495                 :     }
    1496                 : }
    1497                 : 
    1498                 : JSValueType
    1499         1348912 : TypeSet::getKnownTypeTag(JSContext *cx)
    1500                 : {
    1501         1348912 :     TypeFlags flags = baseFlags();
    1502                 :     JSValueType type;
    1503                 : 
    1504         1348912 :     if (baseObjectCount())
    1505          297787 :         type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
    1506                 :     else
    1507         1051125 :         type = GetValueTypeFromTypeFlags(flags);
    1508                 : 
    1509                 :     /*
    1510                 :      * If the type set is totally empty then it will be treated as unknown,
    1511                 :      * but we still need to record the dependency as adding a new type can give
    1512                 :      * it a definite type tag. This is not needed if there are enough types
    1513                 :      * that the exact tag is unknown, as it will stay unknown as more types are
    1514                 :      * added to the set.
    1515                 :      */
    1516         1348912 :     bool empty = flags == 0 && baseObjectCount() == 0;
    1517         1348912 :     JS_ASSERT_IF(empty, type == JSVAL_TYPE_UNKNOWN);
    1518                 : 
    1519         1348912 :     if (cx->compartment->types.compiledInfo.script && (empty || type != JSVAL_TYPE_UNKNOWN)) {
    1520         1218130 :         add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeTypeTag>(
    1521         2436260 :                   cx->compartment->types.compiledInfo), false);
    1522                 :     }
    1523                 : 
    1524         1348912 :     return type;
    1525                 : }
    1526                 : 
    1527                 : /* Constraint which triggers recompilation if an object acquires particular flags. */
    1528                 : class TypeConstraintFreezeObjectFlags : public TypeConstraint
    1529                 : {
    1530                 : public:
    1531                 :     RecompileInfo info;
    1532                 : 
    1533                 :     /* Flags we are watching for on this object. */
    1534                 :     TypeObjectFlags flags;
    1535                 : 
    1536                 :     /* Whether the object has already been marked as having one of the flags. */
    1537                 :     bool *pmarked;
    1538                 :     bool localMarked;
    1539                 : 
    1540          145118 :     TypeConstraintFreezeObjectFlags(RecompileInfo info, TypeObjectFlags flags, bool *pmarked)
    1541                 :         : TypeConstraint("freezeObjectFlags"), info(info), flags(flags),
    1542          145118 :           pmarked(pmarked), localMarked(false)
    1543          145118 :     {}
    1544                 : 
    1545           78550 :     TypeConstraintFreezeObjectFlags(RecompileInfo info, TypeObjectFlags flags)
    1546                 :         : TypeConstraint("freezeObjectFlags"), info(info), flags(flags),
    1547           78550 :           pmarked(&localMarked), localMarked(false)
    1548           78550 :     {}
    1549                 : 
    1550              82 :     void newType(JSContext *cx, TypeSet *source, Type type) {}
    1551                 : 
    1552          120532 :     void newObjectState(JSContext *cx, TypeObject *object, bool force)
    1553                 :     {
    1554          120532 :         if (object->hasAnyFlags(flags) && !*pmarked) {
    1555            5818 :             *pmarked = true;
    1556            5818 :             cx->compartment->types.addPendingRecompile(cx, info);
    1557          114714 :         } else if (force) {
    1558          113967 :             cx->compartment->types.addPendingRecompile(cx, info);
    1559                 :         }
    1560          120532 :     }
    1561                 : };
    1562                 : 
    1563                 : /*
    1564                 :  * Constraint which triggers recompilation if any object in a type set acquire
    1565                 :  * particular flags.
    1566                 :  */
    1567                 : class TypeConstraintFreezeObjectFlagsSet : public TypeConstraint
    1568                 : {
    1569                 : public:
    1570                 :     RecompileInfo info;
    1571                 : 
    1572                 :     TypeObjectFlags flags;
    1573                 :     bool marked;
    1574                 : 
    1575           70130 :     TypeConstraintFreezeObjectFlagsSet(RecompileInfo info, TypeObjectFlags flags)
    1576           70130 :         : TypeConstraint("freezeObjectKindSet"), info(info), flags(flags), marked(false)
    1577           70130 :     {}
    1578                 : 
    1579          158498 :     void newType(JSContext *cx, TypeSet *source, Type type)
    1580                 :     {
    1581          158498 :         if (marked) {
    1582                 :             /* Despecialized the kind we were interested in due to recompilation. */
    1583             630 :             return;
    1584                 :         }
    1585                 : 
    1586          157868 :         if (type.isUnknown() || type.isAnyObject()) {
    1587                 :             /* Fallthrough and recompile. */
    1588          154750 :         } else if (type.isObject()) {
    1589          145462 :             TypeObject *object = type.isSingleObject()
    1590               9 :                 ? type.singleObject()->getType(cx)
    1591          145471 :                 : type.typeObject();
    1592          145462 :             if (!object->hasAnyFlags(flags)) {
    1593                 :                 /*
    1594                 :                  * Add a constraint on the the object to pick up changes in the
    1595                 :                  * object's properties.
    1596                 :                  */
    1597          145118 :                 TypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
    1598          145118 :                 if (!types)
    1599               0 :                     return;
    1600          145118 :                 types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
    1601          290236 :                                   info, flags, &marked), false);
    1602          145118 :                 return;
    1603                 :             }
    1604                 :         } else {
    1605            9288 :             return;
    1606                 :         }
    1607                 : 
    1608            3462 :         marked = true;
    1609            3462 :         cx->compartment->types.addPendingRecompile(cx, info);
    1610                 :     }
    1611                 : };
    1612                 : 
    1613                 : bool
    1614          102008 : TypeSet::hasObjectFlags(JSContext *cx, TypeObjectFlags flags)
    1615                 : {
    1616          102008 :     if (unknownObject())
    1617            4848 :         return true;
    1618                 : 
    1619                 :     /*
    1620                 :      * Treat type sets containing no objects as having all object flags,
    1621                 :      * to spare callers from having to check this.
    1622                 :      */
    1623           97160 :     if (baseObjectCount() == 0)
    1624           14688 :         return true;
    1625                 : 
    1626           82472 :     unsigned count = getObjectCount();
    1627          213133 :     for (unsigned i = 0; i < count; i++) {
    1628          143003 :         TypeObject *object = getTypeObject(i);
    1629          143003 :         if (!object) {
    1630           29998 :             JSObject *obj = getSingleObject(i);
    1631           29998 :             if (obj)
    1632             269 :                 object = obj->getType(cx);
    1633                 :         }
    1634          143003 :         if (object && object->hasAnyFlags(flags))
    1635           12342 :             return true;
    1636                 :     }
    1637                 : 
    1638                 :     /*
    1639                 :      * Watch for new objects of different kind, and re-traverse existing types
    1640                 :      * in this set to add any needed FreezeArray constraints.
    1641                 :      */
    1642           70130 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlagsSet>(
    1643          140260 :                  cx->compartment->types.compiledInfo, flags));
    1644                 : 
    1645           70130 :     return false;
    1646                 : }
    1647                 : 
    1648                 : bool
    1649           66559 : TypeSet::HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags)
    1650                 : {
    1651           66559 :     if (object->hasAnyFlags(flags))
    1652           11125 :         return true;
    1653                 : 
    1654           55434 :     TypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
    1655           55434 :     if (!types)
    1656               0 :         return true;
    1657           55434 :     types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
    1658          110868 :                       cx->compartment->types.compiledInfo, flags), false);
    1659           55434 :     return false;
    1660                 : }
    1661                 : 
    1662                 : void
    1663            4142 : types::MarkArgumentsCreated(JSContext *cx, JSScript *script)
    1664                 : {
    1665            4142 :     JS_ASSERT(!script->createdArgs);
    1666                 : 
    1667            4142 :     script->createdArgs = true;
    1668            4142 :     script->uninlineable = true;
    1669                 : 
    1670            4142 :     MarkTypeObjectFlags(cx, script->function(),
    1671            4142 :                         OBJECT_FLAG_CREATED_ARGUMENTS | OBJECT_FLAG_UNINLINEABLE);
    1672                 : 
    1673            4142 :     if (!script->usedLazyArgs)
    1674            4126 :         return;
    1675                 : 
    1676              32 :     AutoEnterTypeInference enter(cx);
    1677                 : 
    1678                 : #ifdef JS_METHODJIT
    1679              16 :     mjit::ExpandInlineFrames(cx->compartment);
    1680                 : #endif
    1681                 : 
    1682              16 :     if (!script->ensureRanAnalysis(cx, NULL))
    1683                 :         return;
    1684                 : 
    1685              16 :     ScriptAnalysis *analysis = script->analysis();
    1686                 : 
    1687              54 :     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
    1688              38 :         StackFrame *fp = iter.fp();
    1689              38 :         if (fp->isScriptFrame() && fp->script() == script) {
    1690                 :             /*
    1691                 :              * Check locals and stack slots, assignment to individual arguments
    1692                 :              * is treated as an escape on the arguments.
    1693                 :              */
    1694              16 :             Value *sp = fp->base() + analysis->getCode(iter.pc()).stackDepth;
    1695              94 :             for (Value *vp = fp->slots(); vp < sp; vp++) {
    1696              78 :                 if (vp->isParticularMagic(JS_LAZY_ARGUMENTS))
    1697              27 :                     *vp = ObjectOrNullValue(js_GetArgsObject(cx, fp));
    1698                 :             }
    1699                 :         }
    1700                 :     }
    1701                 : }
    1702                 : 
    1703                 : static inline void
    1704          224103 : ObjectStateChange(JSContext *cx, TypeObject *object, bool markingUnknown, bool force)
    1705                 : {
    1706          224103 :     if (object->unknownProperties())
    1707               2 :         return;
    1708                 : 
    1709                 :     /* All constraints listening to state changes are on the empty id. */
    1710          224101 :     TypeSet *types = object->maybeGetProperty(cx, JSID_EMPTY);
    1711                 : 
    1712                 :     /* Mark as unknown after getting the types, to avoid assertion. */
    1713          224101 :     if (markingUnknown)
    1714           26120 :         object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES;
    1715                 : 
    1716          224101 :     if (types) {
    1717           21644 :         TypeConstraint *constraint = types->constraintList;
    1718          170024 :         while (constraint) {
    1719          126736 :             constraint->newObjectState(cx, object, force);
    1720          126736 :             constraint = constraint->next;
    1721                 :         }
    1722                 :     }
    1723                 : }
    1724                 : 
    1725                 : void
    1726           23116 : TypeSet::WatchObjectStateChange(JSContext *cx, TypeObject *obj)
    1727                 : {
    1728           23116 :     JS_ASSERT(!obj->unknownProperties());
    1729           23116 :     TypeSet *types = obj->getProperty(cx, JSID_EMPTY, false);
    1730           23116 :     if (!types)
    1731               0 :         return;
    1732                 : 
    1733                 :     /*
    1734                 :      * Use a constraint which triggers recompilation when markStateChange is
    1735                 :      * called, which will set 'force' to true.
    1736                 :      */
    1737           23116 :     types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
    1738                 :                      cx->compartment->types.compiledInfo,
    1739           46232 :                      0));
    1740                 : }
    1741                 : 
    1742                 : class TypeConstraintFreezeOwnProperty : public TypeConstraint
    1743                 : {
    1744                 : public:
    1745                 :     RecompileInfo info;
    1746                 : 
    1747                 :     bool updated;
    1748                 :     bool configurable;
    1749                 : 
    1750          214987 :     TypeConstraintFreezeOwnProperty(RecompileInfo info, bool configurable)
    1751                 :         : TypeConstraint("freezeOwnProperty"),
    1752          214987 :           info(info), updated(false), configurable(configurable)
    1753          214987 :     {}
    1754                 : 
    1755           17997 :     void newType(JSContext *cx, TypeSet *source, Type type) {}
    1756                 : 
    1757             260 :     void newPropertyState(JSContext *cx, TypeSet *source)
    1758                 :     {
    1759             260 :         if (updated)
    1760               0 :             return;
    1761             260 :         if (source->isOwnProperty(configurable)) {
    1762             246 :             updated = true;
    1763             246 :             cx->compartment->types.addPendingRecompile(cx, info);
    1764                 :         }
    1765                 :     }
    1766                 : };
    1767                 : 
    1768                 : static void
    1769                 : CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun);
    1770                 : 
    1771                 : bool
    1772          215670 : TypeSet::isOwnProperty(JSContext *cx, TypeObject *object, bool configurable)
    1773                 : {
    1774                 :     /*
    1775                 :      * Everywhere compiled code depends on definite properties associated with
    1776                 :      * a type object's newScript, we need to make sure there are constraints
    1777                 :      * in place which will mark those properties as configured should the
    1778                 :      * definite properties be invalidated.
    1779                 :      */
    1780          215670 :     if (object->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
    1781               2 :         if (object->newScript) {
    1782               2 :             CheckNewScriptProperties(cx, object, object->newScript->fun);
    1783                 :         } else {
    1784               0 :             JS_ASSERT(object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED);
    1785               0 :             object->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
    1786                 :         }
    1787                 :     }
    1788                 : 
    1789          215670 :     if (isOwnProperty(configurable))
    1790             683 :         return true;
    1791                 : 
    1792          214987 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeOwnProperty>(
    1793                 :                                                       cx->compartment->types.compiledInfo,
    1794          429974 :                                                       configurable), false);
    1795          214987 :     return false;
    1796                 : }
    1797                 : 
    1798                 : bool
    1799           70939 : TypeSet::knownNonEmpty(JSContext *cx)
    1800                 : {
    1801           70939 :     if (baseFlags() != 0 || baseObjectCount() != 0)
    1802              36 :         return true;
    1803                 : 
    1804           70903 :     addFreeze(cx);
    1805                 : 
    1806           70903 :     return false;
    1807                 : }
    1808                 : 
    1809                 : bool
    1810              24 : TypeSet::knownSubset(JSContext *cx, TypeSet *other)
    1811                 : {
    1812              24 :     if ((baseFlags() & other->baseFlags()) != baseFlags())
    1813               2 :         return false;
    1814                 : 
    1815              22 :     if (unknownObject()) {
    1816               0 :         JS_ASSERT(other->unknownObject());
    1817                 :     } else {
    1818              22 :         for (unsigned i = 0; i < getObjectCount(); i++) {
    1819               0 :             TypeObjectKey *obj = getObject(i);
    1820               0 :             if (!obj)
    1821               0 :                 continue;
    1822               0 :             if (!other->hasType(Type::ObjectType(obj)))
    1823               0 :                 return false;
    1824                 :         }
    1825                 :     }
    1826                 : 
    1827              22 :     addFreeze(cx);
    1828                 : 
    1829              22 :     return true;
    1830                 : }
    1831                 : 
    1832                 : int
    1833            2332 : TypeSet::getTypedArrayType(JSContext *cx)
    1834                 : {
    1835            2332 :     int arrayType = TypedArray::TYPE_MAX;
    1836            2332 :     unsigned count = getObjectCount();
    1837                 : 
    1838            4776 :     for (unsigned i = 0; i < count; i++) {
    1839            2738 :         JSObject *proto = NULL;
    1840            2738 :         if (JSObject *object = getSingleObject(i)) {
    1841               0 :             proto = object->getProto();
    1842            2738 :         } else if (TypeObject *object = getTypeObject(i)) {
    1843            2738 :             JS_ASSERT(!object->hasAnyFlags(OBJECT_FLAG_NON_TYPED_ARRAY));
    1844            2738 :             proto = object->proto;
    1845                 :         }
    1846            2738 :         if (!proto)
    1847               0 :             continue;
    1848                 : 
    1849            2738 :         int objArrayType = proto->getClass() - TypedArray::slowClasses;
    1850            2738 :         JS_ASSERT(objArrayType >= 0 && objArrayType < TypedArray::TYPE_MAX);
    1851                 : 
    1852                 :         /*
    1853                 :          * Set arrayType to the type of the first array. Return if there is an array
    1854                 :          * of another type.
    1855                 :          */
    1856            2738 :         if (arrayType == TypedArray::TYPE_MAX)
    1857            2332 :             arrayType = objArrayType;
    1858             406 :         else if (arrayType != objArrayType)
    1859             294 :             return TypedArray::TYPE_MAX;
    1860                 :     }
    1861                 : 
    1862                 :     /*
    1863                 :      * Assume the caller checked that OBJECT_FLAG_NON_TYPED_ARRAY is not set.
    1864                 :      * This means the set contains at least one object because sets with no
    1865                 :      * objects have all object flags.
    1866                 :      */
    1867            2038 :     JS_ASSERT(arrayType != TypedArray::TYPE_MAX);
    1868                 : 
    1869                 :     /* Recompile when another typed array is added to this set. */
    1870            2038 :     addFreeze(cx);
    1871                 : 
    1872            2038 :     return arrayType;
    1873                 : }
    1874                 : 
    1875                 : JSObject *
    1876          522096 : TypeSet::getSingleton(JSContext *cx, bool freeze)
    1877                 : {
    1878          522096 :     if (baseFlags() != 0 || baseObjectCount() != 1)
    1879          345212 :         return NULL;
    1880                 : 
    1881          176884 :     JSObject *obj = getSingleObject(0);
    1882          176884 :     if (!obj)
    1883           88813 :         return NULL;
    1884                 : 
    1885           88071 :     if (freeze) {
    1886           87985 :         add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreeze>(
    1887          175970 :                                                cx->compartment->types.compiledInfo), false);
    1888                 :     }
    1889                 : 
    1890           88071 :     return obj;
    1891                 : }
    1892                 : 
    1893                 : static inline bool
    1894               0 : TypeHasGlobal(Type type, JSObject *global)
    1895                 : {
    1896               0 :     if (type.isUnknown() || type.isAnyObject())
    1897               0 :         return false;
    1898                 : 
    1899               0 :     if (type.isSingleObject())
    1900               0 :         return &type.singleObject()->global() == global;
    1901                 : 
    1902               0 :     if (type.isTypeObject())
    1903               0 :         return type.typeObject()->getGlobal() == global;
    1904                 : 
    1905               0 :     JS_ASSERT(type.isPrimitive());
    1906               0 :     return true;
    1907                 : }
    1908                 : 
    1909                 : class TypeConstraintFreezeGlobal : public TypeConstraint
    1910                 : {
    1911                 : public:
    1912                 :     RecompileInfo info;
    1913                 :     JSObject *global;
    1914                 : 
    1915               0 :     TypeConstraintFreezeGlobal(RecompileInfo info, JSObject *global)
    1916               0 :         : TypeConstraint("freezeGlobal"), info(info), global(global)
    1917                 :     {
    1918               0 :         JS_ASSERT(global);
    1919               0 :     }
    1920                 : 
    1921               0 :     void newType(JSContext *cx, TypeSet *source, Type type)
    1922                 :     {
    1923               0 :         if (!global || TypeHasGlobal(type, global))
    1924               0 :             return;
    1925                 : 
    1926               0 :         global = NULL;
    1927               0 :         cx->compartment->types.addPendingRecompile(cx, info);
    1928                 :     }
    1929                 : };
    1930                 : 
    1931                 : bool
    1932               0 : TypeSet::hasGlobalObject(JSContext *cx, JSObject *global)
    1933                 : {
    1934               0 :     if (unknownObject())
    1935               0 :         return false;
    1936                 : 
    1937               0 :     unsigned count = getObjectCount();
    1938               0 :     for (unsigned i = 0; i < count; i++) {
    1939               0 :         TypeObjectKey *object = getObject(i);
    1940               0 :         if (object && !TypeHasGlobal(Type::ObjectType(object), global))
    1941               0 :             return false;
    1942                 :     }
    1943                 : 
    1944               0 :     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeGlobal>(
    1945               0 :               cx->compartment->types.compiledInfo, global), false);
    1946                 : 
    1947               0 :     return true;
    1948                 : }
    1949                 : 
    1950                 : bool
    1951             143 : TypeSet::needsBarrier(JSContext *cx)
    1952                 : {
    1953             143 :     bool result = unknownObject()
    1954             118 :                || getObjectCount() > 0
    1955             261 :                || hasAnyFlag(TYPE_FLAG_STRING);
    1956             143 :     if (!result)
    1957              68 :         addFreeze(cx);
    1958             143 :     return result;
    1959                 : }
    1960                 : 
    1961                 : /////////////////////////////////////////////////////////////////////
    1962                 : // TypeCompartment
    1963                 : /////////////////////////////////////////////////////////////////////
    1964                 : 
    1965                 : void
    1966           45576 : TypeCompartment::init(JSContext *cx)
    1967                 : {
    1968           45576 :     PodZero(this);
    1969                 : 
    1970           45576 :     if (cx && cx->getRunOptions() & JSOPTION_TYPE_INFERENCE) {
    1971                 : #ifdef JS_METHODJIT
    1972           24938 :         JSC::MacroAssembler masm;
    1973           12469 :         if (masm.supportsFloatingPoint())
    1974                 : #endif
    1975           12469 :             inferenceEnabled = true;
    1976                 :     }
    1977           45576 : }
    1978                 : 
    1979                 : TypeObject *
    1980          671141 : TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
    1981                 :                                JSProtoKey key, JSObject *proto, bool unknown)
    1982                 : {
    1983         1342282 :     RootObject root(cx, &proto);
    1984                 : 
    1985          671141 :     TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
    1986          671141 :     if (!object)
    1987               0 :         return NULL;
    1988          671141 :     new(object) TypeObject(proto, key == JSProto_Function, unknown);
    1989                 : 
    1990          671141 :     if (!cx->typeInferenceEnabled())
    1991          422722 :         object->flags |= OBJECT_FLAG_UNKNOWN_MASK;
    1992                 :     else
    1993          248419 :         object->setFlagsFromKey(cx, key);
    1994                 : 
    1995          671141 :     return object;
    1996                 : }
    1997                 : 
    1998                 : TypeObject *
    1999           14532 : TypeCompartment::newAllocationSiteTypeObject(JSContext *cx, const AllocationSiteKey &key)
    2000                 : {
    2001           29064 :     AutoEnterTypeInference enter(cx);
    2002                 : 
    2003           14532 :     if (!allocationSiteTable) {
    2004            5008 :         allocationSiteTable = cx->new_<AllocationSiteTable>();
    2005            5008 :         if (!allocationSiteTable || !allocationSiteTable->init()) {
    2006               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2007               0 :             return NULL;
    2008                 :         }
    2009                 :     }
    2010                 : 
    2011           14532 :     AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key);
    2012           14532 :     JS_ASSERT(!p);
    2013                 : 
    2014                 :     JSObject *proto;
    2015           14532 :     if (!js_GetClassPrototype(cx, key.script->global(), key.kind, &proto, NULL))
    2016               0 :         return NULL;
    2017                 : 
    2018           14532 :     TypeObject *res = newTypeObject(cx, key.script, key.kind, proto);
    2019           14532 :     if (!res) {
    2020               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2021               0 :         return NULL;
    2022                 :     }
    2023                 : 
    2024           14532 :     jsbytecode *pc = key.script->code + key.offset;
    2025                 : 
    2026           14532 :     if (JSOp(*pc) == JSOP_NEWOBJECT) {
    2027                 :         /*
    2028                 :          * This object is always constructed the same way and will not be
    2029                 :          * observed by other code before all properties have been added. Mark
    2030                 :          * all the properties as definite properties of the object.
    2031                 :          */
    2032            4827 :         JSObject *baseobj = key.script->getObject(GET_UINT32_INDEX(pc));
    2033                 : 
    2034            4827 :         if (!res->addDefiniteProperties(cx, baseobj))
    2035               0 :             return NULL;
    2036                 :     }
    2037                 : 
    2038           14532 :     if (!allocationSiteTable->add(p, key, res)) {
    2039               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2040               0 :         return NULL;
    2041                 :     }
    2042                 : 
    2043           14532 :     return res;
    2044                 : }
    2045                 : 
    2046                 : static inline jsid
    2047          509640 : GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
    2048                 : {
    2049          509640 :     JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc + offset));
    2050          509640 :     return MakeTypeId(cx, ATOM_TO_JSID(atom));
    2051                 : }
    2052                 : 
    2053                 : bool
    2054         5619386 : types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
    2055                 : {
    2056         5619386 :     JS_ASSERT(cx->typeInferenceEnabled());
    2057                 : 
    2058                 :     /*
    2059                 :      * Make a heuristic guess at a use of JSOP_NEW that the constructed object
    2060                 :      * should have a fresh type object. We do this when the NEW is immediately
    2061                 :      * followed by a simple assignment to an object's .prototype field.
    2062                 :      * This is designed to catch common patterns for subclassing in JS:
    2063                 :      *
    2064                 :      * function Super() { ... }
    2065                 :      * function Sub1() { ... }
    2066                 :      * function Sub2() { ... }
    2067                 :      *
    2068                 :      * Sub1.prototype = new Super();
    2069                 :      * Sub2.prototype = new Super();
    2070                 :      *
    2071                 :      * Using distinct type objects for the particular prototypes of Sub1 and
    2072                 :      * Sub2 lets us continue to distinguish the two subclasses and any extra
    2073                 :      * properties added to those prototype objects.
    2074                 :      */
    2075         5619386 :     if (JSOp(*pc) != JSOP_NEW)
    2076         4747500 :         return false;
    2077          871886 :     pc += JSOP_NEW_LENGTH;
    2078          871886 :     if (JSOp(*pc) == JSOP_SETPROP) {
    2079           24501 :         jsid id = GetAtomId(cx, script, pc, 0);
    2080           24501 :         if (id == id_prototype(cx))
    2081              55 :             return true;
    2082                 :     }
    2083                 : 
    2084          871831 :     return false;
    2085                 : }
    2086                 : 
    2087                 : bool
    2088           35518 : types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
    2089                 : {
    2090           35518 :     if (!cx->typeInferenceEnabled() || !script->hasGlobal())
    2091              24 :         return true;
    2092                 : 
    2093           35494 :     JSObject *proto = script->global()->getOrCreateArrayPrototype(cx);
    2094           35494 :     if (!proto)
    2095               0 :         return true;
    2096                 : 
    2097           70903 :     do {
    2098           70950 :         TypeObject *type = proto->getType(cx);
    2099           70950 :         if (type->unknownProperties())
    2100               6 :             return true;
    2101           70944 :         TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
    2102           70944 :         if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
    2103              41 :             return true;
    2104           70903 :         proto = proto->getProto();
    2105                 :     } while (proto);
    2106                 : 
    2107           35447 :     return false;
    2108                 : }
    2109                 : 
    2110                 : bool
    2111            7819 : TypeCompartment::growPendingArray(JSContext *cx)
    2112                 : {
    2113            7819 :     unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2);
    2114            7819 :     PendingWork *newArray = (PendingWork *) OffTheBooks::calloc_(newCapacity * sizeof(PendingWork));
    2115            7819 :     if (!newArray) {
    2116               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2117               0 :         return false;
    2118                 :     }
    2119                 : 
    2120            7819 :     PodCopy(newArray, pendingArray, pendingCount);
    2121            7819 :     cx->free_(pendingArray);
    2122                 : 
    2123            7819 :     pendingArray = newArray;
    2124            7819 :     pendingCapacity = newCapacity;
    2125                 : 
    2126            7819 :     return true;
    2127                 : }
    2128                 : 
    2129                 : void
    2130           32646 : TypeCompartment::processPendingRecompiles(JSContext *cx)
    2131                 : {
    2132                 :     /* Steal the list of scripts to recompile, else we will try to recursively recompile them. */
    2133           32646 :     Vector<RecompileInfo> *pending = pendingRecompiles;
    2134           32646 :     pendingRecompiles = NULL;
    2135                 : 
    2136           32646 :     JS_ASSERT(!pending->empty());
    2137                 : 
    2138                 : #ifdef JS_METHODJIT
    2139                 : 
    2140           32646 :     mjit::ExpandInlineFrames(cx->compartment);
    2141                 : 
    2142           66079 :     for (unsigned i = 0; i < pending->length(); i++) {
    2143           33433 :         const RecompileInfo &info = (*pending)[i];
    2144           33433 :         mjit::JITScript *jit = info.script->getJIT(info.constructing);
    2145           33433 :         if (jit && jit->chunkDescriptor(info.chunkIndex).chunk)
    2146           33433 :             mjit::Recompiler::clearStackReferencesAndChunk(cx, info.script, jit, info.chunkIndex);
    2147                 :     }
    2148                 : 
    2149                 : #endif /* JS_METHODJIT */
    2150                 : 
    2151           32646 :     cx->delete_(pending);
    2152           32646 : }
    2153                 : 
    2154                 : void
    2155               0 : TypeCompartment::setPendingNukeTypes(JSContext *cx)
    2156                 : {
    2157               0 :     JS_ASSERT(compartment()->activeInference);
    2158               0 :     if (!pendingNukeTypes) {
    2159               0 :         if (cx->compartment)
    2160               0 :             js_ReportOutOfMemory(cx);
    2161               0 :         pendingNukeTypes = true;
    2162                 :     }
    2163               0 : }
    2164                 : 
    2165                 : void
    2166               0 : TypeCompartment::nukeTypes(JSContext *cx)
    2167                 : {
    2168               0 :     JS_ASSERT(this == &cx->compartment->types);
    2169                 : 
    2170                 :     /*
    2171                 :      * This is the usual response if we encounter an OOM while adding a type
    2172                 :      * or resolving type constraints. Reset the compartment to not use type
    2173                 :      * inference, and recompile all scripts.
    2174                 :      *
    2175                 :      * Because of the nature of constraint-based analysis (add constraints, and
    2176                 :      * iterate them until reaching a fixpoint), we can't undo an add of a type set,
    2177                 :      * and merely aborting the operation which triggered the add will not be
    2178                 :      * sufficient for correct behavior as we will be leaving the types in an
    2179                 :      * inconsistent state.
    2180                 :      */
    2181               0 :     JS_ASSERT(pendingNukeTypes);
    2182               0 :     if (pendingRecompiles) {
    2183               0 :         cx->free_(pendingRecompiles);
    2184               0 :         pendingRecompiles = NULL;
    2185                 :     }
    2186                 : 
    2187               0 :     inferenceEnabled = false;
    2188                 : 
    2189                 :     /* Update the cached inferenceEnabled bit in all contexts. */
    2190               0 :     for (ContextIter acx(cx->runtime); !acx.done(); acx.next())
    2191               0 :         acx->setCompartment(acx->compartment);
    2192                 : 
    2193                 : #ifdef JS_METHODJIT
    2194                 : 
    2195               0 :     JSCompartment *compartment = cx->compartment;
    2196               0 :     mjit::ExpandInlineFrames(compartment);
    2197               0 :     mjit::ClearAllFrames(compartment);
    2198                 : 
    2199                 :     /* Throw away all JIT code in the compartment, but leave everything else alone. */
    2200                 : 
    2201               0 :     for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
    2202               0 :         JSScript *script = i.get<JSScript>();
    2203               0 :         if (script->hasJITCode())
    2204               0 :             mjit::ReleaseScriptCode(cx, script);
    2205                 :     }
    2206                 : #endif /* JS_METHODJIT */
    2207                 : 
    2208               0 : }
    2209                 : 
    2210                 : void
    2211          684180 : TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
    2212                 : {
    2213                 : #ifdef JS_METHODJIT
    2214          684180 :     mjit::JITScript *jit = info.script->getJIT(info.constructing);
    2215          684180 :     if (!jit || !jit->chunkDescriptor(info.chunkIndex).chunk) {
    2216                 :         /* Scripts which haven't been compiled yet don't need to be recompiled. */
    2217          459101 :         return;
    2218                 :     }
    2219                 : 
    2220          225079 :     if (!pendingRecompiles) {
    2221           32646 :         pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
    2222           32646 :         if (!pendingRecompiles) {
    2223               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2224               0 :             return;
    2225                 :         }
    2226                 :     }
    2227                 : 
    2228          292668 :     for (unsigned i = 0; i < pendingRecompiles->length(); i++) {
    2229          259235 :         if (info == (*pendingRecompiles)[i])
    2230          191646 :             return;
    2231                 :     }
    2232                 : 
    2233           33433 :     if (!pendingRecompiles->append(info)) {
    2234               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2235               0 :         return;
    2236                 :     }
    2237                 : #endif
    2238                 : }
    2239                 : 
    2240                 : void
    2241          486166 : TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc)
    2242                 : {
    2243                 : #ifdef JS_METHODJIT
    2244                 :     RecompileInfo info;
    2245          486166 :     info.script = script;
    2246                 : 
    2247          486166 :     if (script->jitNormal) {
    2248           67521 :         info.constructing = false;
    2249           67521 :         info.chunkIndex = script->jitNormal->chunkIndex(pc);
    2250           67521 :         addPendingRecompile(cx, info);
    2251                 :     }
    2252                 : 
    2253          486166 :     if (script->jitCtor) {
    2254             650 :         info.constructing = true;
    2255             650 :         info.chunkIndex = script->jitCtor->chunkIndex(pc);
    2256             650 :         addPendingRecompile(cx, info);
    2257                 :     }
    2258                 : #endif
    2259          486166 : }
    2260                 : 
    2261                 : void
    2262           47649 : TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
    2263                 :                                  bool returnOnly)
    2264                 : {
    2265           47649 :     ScriptAnalysis *analysis = script->analysis();
    2266           47649 :     JS_ASSERT(analysis->ranInference());
    2267                 : 
    2268           47649 :     jsbytecode *pc = script->code + offset;
    2269                 : 
    2270           47649 :     JS_ASSERT_IF(returnOnly, js_CodeSpec[*pc].format & JOF_INVOKE);
    2271                 : 
    2272           47649 :     Bytecode &code = analysis->getCode(pc);
    2273                 : 
    2274           47649 :     if (returnOnly ? code.monitoredTypesReturn : code.monitoredTypes)
    2275            3008 :         return;
    2276                 : 
    2277                 :     InferSpew(ISpewOps, "addMonitorNeeded:%s #%u:%05u",
    2278           44641 :               returnOnly ? " returnOnly" : "", script->id(), offset);
    2279                 : 
    2280                 :     /* Dynamically monitor this call to keep track of its result types. */
    2281           44641 :     if (js_CodeSpec[*pc].format & JOF_INVOKE)
    2282           33452 :         code.monitoredTypesReturn = true;
    2283                 : 
    2284           44641 :     if (!returnOnly)
    2285           14450 :         code.monitoredTypes = true;
    2286                 : 
    2287           44641 :     cx->compartment->types.addPendingRecompile(cx, script, pc);
    2288                 : 
    2289                 :     /* Trigger recompilation of any inline callers. */
    2290           44641 :     if (script->function() && !script->function()->hasLazyType())
    2291           11373 :         ObjectStateChange(cx, script->function()->type(), false, true);
    2292                 : }
    2293                 : 
    2294                 : void
    2295             165 : TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
    2296                 : {
    2297             165 :     JS_ASSERT(this == &cx->compartment->types);
    2298             165 :     JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
    2299             165 :     JS_ASSERT(!target->singleton);
    2300             165 :     JS_ASSERT(target->unknownProperties());
    2301             165 :     target->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
    2302                 : 
    2303             330 :     AutoEnterTypeInference enter(cx);
    2304                 : 
    2305                 :     /*
    2306                 :      * Mark both persistent and transient type sets which contain obj as having
    2307                 :      * a generic object type. It is not sufficient to mark just the persistent
    2308                 :      * sets, as analysis of individual opcodes can pull type objects from
    2309                 :      * static information (like initializer objects at various offsets).
    2310                 :      * 
    2311                 :      * We make a list of properties to update and fix them afterwards, as adding
    2312                 :      * types can't be done while iterating over cells as it can potentially make
    2313                 :      * new type objects as well or trigger GC.
    2314                 :      */
    2315             330 :     Vector<TypeSet *> pending(cx);
    2316            3962 :     for (gc::CellIter i(cx->compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
    2317            3797 :         TypeObject *object = i.get<TypeObject>();
    2318                 : 
    2319            3797 :         unsigned count = object->getPropertyCount();
    2320            4959 :         for (unsigned i = 0; i < count; i++) {
    2321            1162 :             Property *prop = object->getProperty(i);
    2322            1162 :             if (prop && prop->types.hasType(Type::ObjectType(target))) {
    2323             206 :                 if (!pending.append(&prop->types))
    2324               0 :                     cx->compartment->types.setPendingNukeTypes(cx);
    2325                 :             }
    2326                 :         }
    2327                 :     }
    2328                 : 
    2329             371 :     for (unsigned i = 0; i < pending.length(); i++)
    2330             206 :         pending[i]->addType(cx, Type::AnyObjectType());
    2331                 : 
    2332            1120 :     for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
    2333             955 :         JSScript *script = i.get<JSScript>();
    2334             955 :         if (script->types) {
    2335             409 :             unsigned count = TypeScript::NumTypeSets(script);
    2336             409 :             TypeSet *typeArray = script->types->typeArray();
    2337            2819 :             for (unsigned i = 0; i < count; i++) {
    2338            2410 :                 if (typeArray[i].hasType(Type::ObjectType(target)))
    2339             290 :                     typeArray[i].addType(cx, Type::AnyObjectType());
    2340                 :             }
    2341                 :         }
    2342             955 :         if (script->hasAnalysis() && script->analysis()->ranInference()) {
    2343           11860 :             for (unsigned i = 0; i < script->length; i++) {
    2344           11697 :                 if (!script->analysis()->maybeCode(i))
    2345            7778 :                     continue;
    2346            3919 :                 jsbytecode *pc = script->code + i;
    2347            3919 :                 if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
    2348              18 :                     continue;
    2349            3901 :                 unsigned defCount = GetDefCount(script, i);
    2350            3901 :                 if (ExtendedDef(pc))
    2351             108 :                     defCount++;
    2352            6719 :                 for (unsigned j = 0; j < defCount; j++) {
    2353            2818 :                     TypeSet *types = script->analysis()->pushedTypes(pc, j);
    2354            2818 :                     if (types->hasType(Type::ObjectType(target)))
    2355             276 :                         types->addType(cx, Type::AnyObjectType());
    2356                 :                 }
    2357                 :             }
    2358                 :         }
    2359                 :     }
    2360             165 : }
    2361                 : 
    2362                 : void
    2363          538964 : ScriptAnalysis::addTypeBarrier(JSContext *cx, const jsbytecode *pc, TypeSet *target, Type type)
    2364                 : {
    2365          538964 :     Bytecode &code = getCode(pc);
    2366                 : 
    2367         1185224 :     if (!type.isUnknown() && !type.isAnyObject() &&
    2368          646260 :         type.isObject() && target->getObjectCount() >= BARRIER_OBJECT_LIMIT) {
    2369                 :         /* Ignore this barrier, just add the type to the target. */
    2370            2961 :         target->addType(cx, type);
    2371            2961 :         return;
    2372                 :     }
    2373                 : 
    2374          536003 :     if (!code.typeBarriers) {
    2375                 :         /*
    2376                 :          * Adding type barriers at a bytecode which did not have them before
    2377                 :          * will trigger recompilation. If there were already type barriers,
    2378                 :          * however, do not trigger recompilation (the script will be recompiled
    2379                 :          * if any of the barriers is ever violated).
    2380                 :          */
    2381          434319 :         cx->compartment->types.addPendingRecompile(cx, script, const_cast<jsbytecode*>(pc));
    2382                 : 
    2383                 :         /* Trigger recompilation of any inline callers. */
    2384          434319 :         if (script->function() && !script->function()->hasLazyType())
    2385           27543 :             ObjectStateChange(cx, script->function()->type(), false, true);
    2386                 :     }
    2387                 : 
    2388                 :     /* Ignore duplicate barriers. */
    2389          536003 :     TypeBarrier *barrier = code.typeBarriers;
    2390        10121229 :     while (barrier) {
    2391         9052405 :         if (barrier->target == target && barrier->type == type && !barrier->singleton)
    2392            3182 :             return;
    2393         9049223 :         barrier = barrier->next;
    2394                 :     }
    2395                 : 
    2396                 :     InferSpew(ISpewOps, "typeBarrier: #%u:%05u: %sT%p%s %s",
    2397                 :               script->id(), pc - script->code,
    2398                 :               InferSpewColor(target), target, InferSpewColorReset(),
    2399          532821 :               TypeString(type));
    2400                 : 
    2401          532821 :     barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, type, (JSObject *) NULL, JSID_VOID);
    2402                 : 
    2403          532821 :     if (!barrier) {
    2404               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2405               0 :         return;
    2406                 :     }
    2407                 : 
    2408          532821 :     barrier->next = code.typeBarriers;
    2409          532821 :     code.typeBarriers = barrier;
    2410                 : }
    2411                 : 
    2412                 : void
    2413           13080 : ScriptAnalysis::addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc, TypeSet *target, JSObject *singleton, jsid singletonId)
    2414                 : {
    2415           13080 :     JS_ASSERT(singletonId == MakeTypeId(cx, singletonId) && !JSID_IS_VOID(singletonId));
    2416                 : 
    2417           13080 :     Bytecode &code = getCode(pc);
    2418                 : 
    2419           13080 :     if (!code.typeBarriers) {
    2420                 :         /* Trigger recompilation as for normal type barriers. */
    2421            7206 :         cx->compartment->types.addPendingRecompile(cx, script, const_cast<jsbytecode*>(pc));
    2422            7206 :         if (script->function() && !script->function()->hasLazyType())
    2423              95 :             ObjectStateChange(cx, script->function()->type(), false, true);
    2424                 :     }
    2425                 : 
    2426                 :     InferSpew(ISpewOps, "singletonTypeBarrier: #%u:%05u: %sT%p%s %p %s",
    2427                 :               script->id(), pc - script->code,
    2428                 :               InferSpewColor(target), target, InferSpewColorReset(),
    2429           13080 :               (void *) singleton, TypeIdString(singletonId));
    2430                 : 
    2431           13080 :     TypeBarrier *barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(),
    2432           26160 :                               singleton, singletonId);
    2433                 : 
    2434           13080 :     if (!barrier) {
    2435               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2436               0 :         return;
    2437                 :     }
    2438                 : 
    2439           13080 :     barrier->next = code.typeBarriers;
    2440           13080 :     code.typeBarriers = barrier;
    2441                 : }
    2442                 : 
    2443                 : void
    2444           41941 : TypeCompartment::print(JSContext *cx, bool force)
    2445                 : {
    2446           41941 :     JSCompartment *compartment = this->compartment();
    2447           83882 :     AutoEnterAnalysis enter(compartment);
    2448                 : 
    2449           41941 :     if (!force && !InferSpewActive(ISpewResult))
    2450                 :         return;
    2451                 : 
    2452               0 :     for (gc::CellIter i(compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
    2453               0 :         JSScript *script = i.get<JSScript>();
    2454               0 :         if (script->hasAnalysis() && script->analysis()->ranInference())
    2455               0 :             script->analysis()->printTypes(cx);
    2456                 :     }
    2457                 : 
    2458                 : #ifdef DEBUG
    2459               0 :     for (gc::CellIter i(compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
    2460               0 :         TypeObject *object = i.get<TypeObject>();
    2461               0 :         object->print(cx);
    2462                 :     }
    2463                 : #endif
    2464                 : 
    2465               0 :     printf("Counts: ");
    2466               0 :     for (unsigned count = 0; count < TYPE_COUNT_LIMIT; count++) {
    2467               0 :         if (count)
    2468               0 :             printf("/");
    2469               0 :         printf("%u", typeCounts[count]);
    2470                 :     }
    2471               0 :     printf(" (%u over)\n", typeCountOver);
    2472                 : 
    2473               0 :     printf("Recompilations: %u\n", recompilations);
    2474                 : }
    2475                 : 
    2476                 : /////////////////////////////////////////////////////////////////////
    2477                 : // TypeCompartment tables
    2478                 : /////////////////////////////////////////////////////////////////////
    2479                 : 
    2480                 : /*
    2481                 :  * The arrayTypeTable and objectTypeTable are per-compartment tables for making
    2482                 :  * common type objects to model the contents of large script singletons and
    2483                 :  * JSON objects. These are vanilla Arrays and native Objects, so we distinguish
    2484                 :  * the types of different ones by looking at the types of their properties.
    2485                 :  *
    2486                 :  * All singleton/JSON arrays which have the same prototype, are homogenous and
    2487                 :  * of the same element type will share a type object. All singleton/JSON
    2488                 :  * objects which have the same shape and property types will also share a type
    2489                 :  * object. We don't try to collate arrays or objects that have type mismatches.
    2490                 :  */
    2491                 : 
    2492                 : static inline bool
    2493             300 : NumberTypes(Type a, Type b)
    2494                 : {
    2495             545 :     return (a.isPrimitive(JSVAL_TYPE_INT32) || a.isPrimitive(JSVAL_TYPE_DOUBLE))
    2496             545 :         && (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE));
    2497                 : }
    2498                 : 
    2499                 : /*
    2500                 :  * As for GetValueType, but requires object types to be non-singletons with
    2501                 :  * their default prototype. These are the only values that should appear in
    2502                 :  * arrays and objects whose type can be fixed.
    2503                 :  */
    2504                 : static inline Type
    2505           10586 : GetValueTypeForTable(JSContext *cx, const Value &v)
    2506                 : {
    2507           10586 :     Type type = GetValueType(cx, v);
    2508           10586 :     JS_ASSERT(!type.isSingleObject());
    2509                 :     return type;
    2510                 : }
    2511                 : 
    2512                 : struct types::ArrayTableKey
    2513                 : {
    2514                 :     Type type;
    2515                 :     JSObject *proto;
    2516                 : 
    2517           37580 :     ArrayTableKey()
    2518           37580 :         : type(Type::UndefinedType()), proto(NULL)
    2519           37580 :     {}
    2520                 : 
    2521                 :     typedef ArrayTableKey Lookup;
    2522                 : 
    2523            1555 :     static inline uint32_t hash(const ArrayTableKey &v) {
    2524            1555 :         return (uint32_t) (v.type.raw() ^ ((uint32_t)(size_t)v.proto >> 2));
    2525                 :     }
    2526                 : 
    2527             730 :     static inline bool match(const ArrayTableKey &v1, const ArrayTableKey &v2) {
    2528             730 :         return v1.type == v2.type && v1.proto == v2.proto;
    2529                 :     }
    2530                 : };
    2531                 : 
    2532                 : void
    2533            1775 : TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj)
    2534                 : {
    2535            3550 :     AutoEnterTypeInference enter(cx);
    2536                 : 
    2537            1775 :     if (!arrayTypeTable) {
    2538             745 :         arrayTypeTable = cx->new_<ArrayTypeTable>();
    2539             745 :         if (!arrayTypeTable || !arrayTypeTable->init()) {
    2540               0 :             arrayTypeTable = NULL;
    2541               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2542                 :             return;
    2543                 :         }
    2544                 :     }
    2545                 : 
    2546                 :     /*
    2547                 :      * If the array is of homogenous type, pick a type object which will be
    2548                 :      * shared with all other singleton/JSON arrays of the same type.
    2549                 :      * If the array is heterogenous, keep the existing type object, which has
    2550                 :      * unknown properties.
    2551                 :      */
    2552            1775 :     JS_ASSERT(obj->isDenseArray());
    2553                 : 
    2554            1775 :     unsigned len = obj->getDenseArrayInitializedLength();
    2555            1775 :     if (len == 0)
    2556                 :         return;
    2557                 : 
    2558            1755 :     Type type = GetValueTypeForTable(cx, obj->getDenseArrayElement(0));
    2559                 : 
    2560            7610 :     for (unsigned i = 1; i < len; i++) {
    2561            6055 :         Type ntype = GetValueTypeForTable(cx, obj->getDenseArrayElement(i));
    2562            6055 :         if (ntype != type) {
    2563             220 :             if (NumberTypes(type, ntype))
    2564              20 :                 type = Type::DoubleType();
    2565                 :             else
    2566                 :                 return;
    2567                 :         }
    2568                 :     }
    2569                 : 
    2570            1555 :     ArrayTableKey key;
    2571            1555 :     key.type = type;
    2572            1555 :     key.proto = obj->getProto();
    2573            1555 :     ArrayTypeTable::AddPtr p = arrayTypeTable->lookupForAdd(key);
    2574                 : 
    2575            1555 :     if (p) {
    2576             730 :         obj->setType(p->value);
    2577                 :     } else {
    2578                 :         /* Make a new type to use for future arrays with the same elements. */
    2579             825 :         TypeObject *objType = newTypeObject(cx, NULL, JSProto_Array, obj->getProto());
    2580             825 :         if (!objType) {
    2581               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2582                 :             return;
    2583                 :         }
    2584             825 :         obj->setType(objType);
    2585                 : 
    2586             825 :         if (!objType->unknownProperties())
    2587             825 :             objType->addPropertyType(cx, JSID_VOID, type);
    2588                 : 
    2589             825 :         if (!arrayTypeTable->relookupOrAdd(p, key, objType)) {
    2590               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2591                 :             return;
    2592                 :         }
    2593                 :     }
    2594                 : }
    2595                 : 
    2596                 : /*
    2597                 :  * N.B. We could also use the initial shape of the object (before its type is
    2598                 :  * fixed) as the key in the object table, but since all references in the table
    2599                 :  * are weak the hash entries would usually be collected on GC even if objects
    2600                 :  * with the new type/shape are still live.
    2601                 :  */
    2602                 : struct types::ObjectTableKey
    2603                 : {
    2604                 :     jsid *ids;
    2605                 :     uint32_t nslots;
    2606                 :     uint32_t nfixed;
    2607                 :     JSObject *proto;
    2608                 : 
    2609                 :     typedef JSObject * Lookup;
    2610                 : 
    2611            2031 :     static inline uint32_t hash(JSObject *obj) {
    2612            2031 :         return (uint32_t) (JSID_BITS(obj->lastProperty()->propid().get()) ^
    2613            4062 :                          obj->slotSpan() ^ obj->numFixedSlots() ^
    2614            6093 :                          ((uint32_t)(size_t)obj->getProto() >> 2));
    2615                 :     }
    2616                 : 
    2617            1268 :     static inline bool match(const ObjectTableKey &v, JSObject *obj) {
    2618            3804 :         if (obj->slotSpan() != v.nslots ||
    2619            1268 :             obj->numFixedSlots() != v.nfixed ||
    2620            1268 :             obj->getProto() != v.proto) {
    2621               0 :             return false;
    2622                 :         }
    2623            1268 :         const Shape *shape = obj->lastProperty();
    2624            5372 :         while (!shape->isEmptyShape()) {
    2625            2836 :             if (shape->propid() != v.ids[shape->slot()])
    2626               0 :                 return false;
    2627            2836 :             shape = shape->previous();
    2628                 :         }
    2629            1268 :         return true;
    2630                 :     }
    2631                 : };
    2632                 : 
    2633                 : struct types::ObjectTableEntry
    2634           27270 : {
    2635                 :     ReadBarriered<TypeObject> object;
    2636                 :     Type *types;
    2637                 : };
    2638                 : 
    2639                 : void
    2640            1323 : TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
    2641                 : {
    2642            2646 :     AutoEnterTypeInference enter(cx);
    2643                 : 
    2644            1323 :     if (!objectTypeTable) {
    2645             538 :         objectTypeTable = cx->new_<ObjectTypeTable>();
    2646             538 :         if (!objectTypeTable || !objectTypeTable->init()) {
    2647               0 :             objectTypeTable = NULL;
    2648               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2649                 :             return;
    2650                 :         }
    2651                 :     }
    2652                 : 
    2653                 :     /*
    2654                 :      * Use the same type object for all singleton/JSON arrays with the same
    2655                 :      * base shape, i.e. the same fields written in the same order. If there
    2656                 :      * is a type mismatch with previous objects of the same shape, use the
    2657                 :      * generic unknown type.
    2658                 :      */
    2659            1323 :     JS_ASSERT(obj->isObject());
    2660                 : 
    2661            1323 :     if (obj->slotSpan() == 0 || obj->inDictionaryMode())
    2662                 :         return;
    2663                 : 
    2664            1268 :     ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj);
    2665            1268 :     const Shape *baseShape = obj->lastProperty();
    2666                 : 
    2667            1268 :     if (p) {
    2668                 :         /* The lookup ensures the shape matches, now check that the types match. */
    2669             505 :         Type *types = p->value.types;
    2670            1250 :         for (unsigned i = 0; i < obj->slotSpan(); i++) {
    2671             810 :             Type ntype = GetValueTypeForTable(cx, obj->getSlot(i));
    2672             810 :             if (ntype != types[i]) {
    2673              80 :                 if (NumberTypes(ntype, types[i])) {
    2674              15 :                     if (types[i].isPrimitive(JSVAL_TYPE_INT32)) {
    2675              10 :                         types[i] = Type::DoubleType();
    2676              10 :                         const Shape *shape = baseShape;
    2677              20 :                         while (!shape->isEmptyShape()) {
    2678              10 :                             if (shape->slot() == i) {
    2679              10 :                                 Type type = Type::DoubleType();
    2680              10 :                                 if (!p->value.object->unknownProperties()) {
    2681              10 :                                     jsid id = MakeTypeId(cx, shape->propid());
    2682              10 :                                     p->value.object->addPropertyType(cx, id, type);
    2683                 :                                 }
    2684              10 :                                 break;
    2685                 :                             }
    2686               0 :                             shape = shape->previous();
    2687                 :                         }
    2688                 :                     }
    2689                 :                 } else {
    2690                 :                     return;
    2691                 :                 }
    2692                 :             }
    2693                 :         }
    2694                 : 
    2695             440 :         obj->setType(p->value.object);
    2696                 :     } else {
    2697                 :         /* Make a new type to use for the object and similar future ones. */
    2698             763 :         TypeObject *objType = newTypeObject(cx, NULL, JSProto_Object, obj->getProto());
    2699             763 :         if (!objType || !objType->addDefiniteProperties(cx, obj)) {
    2700               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2701                 :             return;
    2702                 :         }
    2703                 : 
    2704             763 :         jsid *ids = (jsid *) cx->calloc_(obj->slotSpan() * sizeof(jsid));
    2705             763 :         if (!ids) {
    2706               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2707                 :             return;
    2708                 :         }
    2709                 : 
    2710             763 :         Type *types = (Type *) cx->calloc_(obj->slotSpan() * sizeof(Type));
    2711             763 :         if (!types) {
    2712               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2713                 :             return;
    2714                 :         }
    2715                 : 
    2716             763 :         const Shape *shape = baseShape;
    2717            3492 :         while (!shape->isEmptyShape()) {
    2718            1966 :             ids[shape->slot()] = shape->propid();
    2719            1966 :             types[shape->slot()] = GetValueTypeForTable(cx, obj->getSlot(shape->slot()));
    2720            1966 :             if (!objType->unknownProperties()) {
    2721            1966 :                 jsid id = MakeTypeId(cx, shape->propid());
    2722            1966 :                 objType->addPropertyType(cx, id, types[shape->slot()]);
    2723                 :             }
    2724            1966 :             shape = shape->previous();
    2725                 :         }
    2726                 : 
    2727                 :         ObjectTableKey key;
    2728             763 :         key.ids = ids;
    2729             763 :         key.nslots = obj->slotSpan();
    2730             763 :         key.nfixed = obj->numFixedSlots();
    2731             763 :         key.proto = obj->getProto();
    2732             763 :         JS_ASSERT(ObjectTableKey::match(key, obj));
    2733                 : 
    2734             763 :         ObjectTableEntry entry;
    2735             763 :         entry.object = objType;
    2736             763 :         entry.types = types;
    2737                 : 
    2738             763 :         p = objectTypeTable->lookupForAdd(obj);
    2739             763 :         if (!objectTypeTable->add(p, key, entry)) {
    2740               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2741                 :             return;
    2742                 :         }
    2743                 : 
    2744             763 :         obj->setType(objType);
    2745                 :     }
    2746                 : }
    2747                 : 
    2748                 : /////////////////////////////////////////////////////////////////////
    2749                 : // TypeObject
    2750                 : /////////////////////////////////////////////////////////////////////
    2751                 : 
    2752                 : void
    2753           96301 : TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force)
    2754                 : {
    2755           96301 :     if (!force && types->hasPropagatedProperty())
    2756            5289 :         return;
    2757                 : 
    2758           91012 :     types->setPropagatedProperty();
    2759                 : 
    2760           91012 :     if (!proto)
    2761           38064 :         return;
    2762                 : 
    2763           52948 :     if (proto->getType(cx)->unknownProperties()) {
    2764             101 :         types->addType(cx, Type::UnknownType());
    2765             101 :         return;
    2766                 :     }
    2767                 : 
    2768           52847 :     TypeSet *protoTypes = proto->type()->getProperty(cx, id, false);
    2769           52847 :     if (!protoTypes)
    2770               0 :         return;
    2771                 : 
    2772           52847 :     protoTypes->addSubset(cx, types);
    2773                 : 
    2774           52847 :     proto->type()->getFromPrototypes(cx, id, protoTypes);
    2775                 : }
    2776                 : 
    2777                 : static inline void
    2778           44922 : UpdatePropertyType(JSContext *cx, TypeSet *types, JSObject *obj, const Shape *shape, bool force)
    2779                 : {
    2780           44922 :     types->setOwnProperty(cx, false);
    2781           44922 :     if (!shape->writable())
    2782            1060 :         types->setOwnProperty(cx, true);
    2783                 : 
    2784           44922 :     if (shape->hasGetterValue() || shape->hasSetterValue()) {
    2785             793 :         types->setOwnProperty(cx, true);
    2786             793 :         types->addType(cx, Type::UnknownType());
    2787           44129 :     } else if (shape->hasDefaultGetterOrIsMethod() && shape->hasSlot()) {
    2788           43453 :         const Value &value = obj->nativeGetSlot(shape->slot());
    2789                 : 
    2790                 :         /*
    2791                 :          * Don't add initial undefined types for singleton properties that are
    2792                 :          * not collated into the JSID_VOID property (see propertySet comment).
    2793                 :          */
    2794           43453 :         if (force || !value.isUndefined()) {
    2795           33146 :             Type type = GetValueType(cx, value);
    2796           33146 :             types->addType(cx, type);
    2797                 :         }
    2798                 :     }
    2799           44922 : }
    2800                 : 
    2801                 : bool
    2802          145677 : TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
    2803                 : {
    2804          145677 :     JS_ASSERT(!*pprop);
    2805          145677 :     Property *base = cx->typeLifoAlloc().new_<Property>(id);
    2806          145677 :     if (!base) {
    2807               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    2808               0 :         return false;
    2809                 :     }
    2810                 : 
    2811          145677 :     if (singleton) {
    2812                 :         /*
    2813                 :          * Fill the property in with any type the object already has in an
    2814                 :          * own property. We are only interested in plain native properties
    2815                 :          * which don't go through a barrier when read by the VM or jitcode.
    2816                 :          * We don't need to handle arrays or other JIT'ed non-natives as
    2817                 :          * these are not (yet) singletons.
    2818                 :          */
    2819                 : 
    2820          106258 :         if (JSID_IS_VOID(id)) {
    2821                 :             /* Go through all shapes on the object to get integer-valued properties. */
    2822            3089 :             const Shape *shape = singleton->lastProperty();
    2823           63517 :             while (!shape->isEmptyShape()) {
    2824           57339 :                 if (JSID_IS_VOID(MakeTypeId(cx, shape->propid())))
    2825             164 :                     UpdatePropertyType(cx, &base->types, singleton, shape, true);
    2826           57339 :                 shape = shape->previous();
    2827                 :             }
    2828          103169 :         } else if (!JSID_IS_EMPTY(id)) {
    2829           91583 :             const Shape *shape = singleton->nativeLookup(cx, id);
    2830           91583 :             if (shape)
    2831           44758 :                 UpdatePropertyType(cx, &base->types, singleton, shape, false);
    2832                 :         }
    2833                 : 
    2834          106258 :         if (singleton->watched()) {
    2835                 :             /*
    2836                 :              * Mark the property as configured, to inhibit optimizations on it
    2837                 :              * and avoid bypassing the watchpoint handler.
    2838                 :              */
    2839               8 :             base->types.setOwnProperty(cx, true);
    2840                 :         }
    2841                 :     }
    2842                 : 
    2843          145677 :     *pprop = base;
    2844                 : 
    2845                 :     InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s",
    2846                 :               InferSpewColor(&base->types), &base->types, InferSpewColorReset(),
    2847          145677 :               TypeObjectString(this), TypeIdString(id));
    2848                 : 
    2849          145677 :     return true;
    2850                 : }
    2851                 : 
    2852                 : bool
    2853            6170 : TypeObject::addDefiniteProperties(JSContext *cx, JSObject *obj)
    2854                 : {
    2855            6170 :     if (unknownProperties())
    2856               0 :         return true;
    2857                 : 
    2858                 :     /* Mark all properties of obj as definite properties of this type. */
    2859           12340 :     AutoEnterTypeInference enter(cx);
    2860                 : 
    2861            6170 :     const Shape *shape = obj->lastProperty();
    2862           19712 :     while (!shape->isEmptyShape()) {
    2863            7372 :         jsid id = MakeTypeId(cx, shape->propid());
    2864           14406 :         if (!JSID_IS_VOID(id) && obj->isFixedSlot(shape->slot()) &&
    2865            7034 :             shape->slot() <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT)) {
    2866            7034 :             TypeSet *types = getProperty(cx, id, true);
    2867            7034 :             if (!types)
    2868               0 :                 return false;
    2869            7034 :             types->setDefinite(shape->slot());
    2870                 :         }
    2871            7372 :         shape = shape->previous();
    2872                 :     }
    2873                 : 
    2874            6170 :     return true;
    2875                 : }
    2876                 : 
    2877                 : bool
    2878               2 : TypeObject::matchDefiniteProperties(JSObject *obj)
    2879                 : {
    2880               2 :     unsigned count = getPropertyCount();
    2881               8 :     for (unsigned i = 0; i < count; i++) {
    2882               6 :         Property *prop = getProperty(i);
    2883               6 :         if (!prop)
    2884               0 :             continue;
    2885               6 :         if (prop->types.isDefiniteProperty()) {
    2886               4 :             unsigned slot = prop->types.definiteSlot();
    2887                 : 
    2888               4 :             bool found = false;
    2889               4 :             const Shape *shape = obj->lastProperty();
    2890              10 :             while (!shape->isEmptyShape()) {
    2891               6 :                 if (shape->slot() == slot && shape->propid() == prop->id) {
    2892               4 :                     found = true;
    2893               4 :                     break;
    2894                 :                 }
    2895               2 :                 shape = shape->previous();
    2896                 :             }
    2897               4 :             if (!found)
    2898               0 :                 return false;
    2899                 :         }
    2900                 :     }
    2901                 : 
    2902               2 :     return true;
    2903                 : }
    2904                 : 
    2905                 : inline void
    2906        13391261 : InlineAddTypeProperty(JSContext *cx, TypeObject *obj, jsid id, Type type)
    2907                 : {
    2908        13391261 :     JS_ASSERT(id == MakeTypeId(cx, id));
    2909                 : 
    2910        26782522 :     AutoEnterTypeInference enter(cx);
    2911                 : 
    2912        13391261 :     TypeSet *types = obj->getProperty(cx, id, true);
    2913        13391261 :     if (!types || types->hasType(type))
    2914                 :         return;
    2915                 : 
    2916                 :     InferSpew(ISpewOps, "externalType: property %s %s: %s",
    2917           25241 :               TypeObjectString(obj), TypeIdString(id), TypeString(type));
    2918           25241 :     types->addType(cx, type);
    2919                 : }
    2920                 : 
    2921                 : void
    2922          275636 : TypeObject::addPropertyType(JSContext *cx, jsid id, Type type)
    2923                 : {
    2924          275636 :     InlineAddTypeProperty(cx, this, id, type);
    2925          275636 : }
    2926                 : 
    2927                 : void
    2928        13097911 : TypeObject::addPropertyType(JSContext *cx, jsid id, const Value &value)
    2929                 : {
    2930        13097911 :     InlineAddTypeProperty(cx, this, id, GetValueType(cx, value));
    2931        13097911 : }
    2932                 : 
    2933                 : void
    2934           17714 : TypeObject::addPropertyType(JSContext *cx, const char *name, Type type)
    2935                 : {
    2936           17714 :     jsid id = JSID_VOID;
    2937           17714 :     if (name) {
    2938            5974 :         JSAtom *atom = js_Atomize(cx, name, strlen(name));
    2939            5974 :         if (!atom) {
    2940               0 :             AutoEnterTypeInference enter(cx);
    2941               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    2942                 :             return;
    2943                 :         }
    2944            5974 :         id = ATOM_TO_JSID(atom);
    2945                 :     }
    2946           17714 :     InlineAddTypeProperty(cx, this, id, type);
    2947                 : }
    2948                 : 
    2949                 : void
    2950               0 : TypeObject::addPropertyType(JSContext *cx, const char *name, const Value &value)
    2951                 : {
    2952               0 :     addPropertyType(cx, name, GetValueType(cx, value));
    2953               0 : }
    2954                 : 
    2955                 : void
    2956          275641 : TypeObject::markPropertyConfigured(JSContext *cx, jsid id)
    2957                 : {
    2958          551282 :     AutoEnterTypeInference enter(cx);
    2959                 : 
    2960          275641 :     id = MakeTypeId(cx, id);
    2961                 : 
    2962          275641 :     TypeSet *types = getProperty(cx, id, true);
    2963          275641 :     if (types)
    2964          275641 :         types->setOwnProperty(cx, true);
    2965          275641 : }
    2966                 : 
    2967                 : void
    2968           12835 : TypeObject::markStateChange(JSContext *cx)
    2969                 : {
    2970           12835 :     if (unknownProperties())
    2971               0 :         return;
    2972                 : 
    2973           25670 :     AutoEnterTypeInference enter(cx);
    2974           12835 :     TypeSet *types = maybeGetProperty(cx, JSID_EMPTY);
    2975           12835 :     if (types) {
    2976              28 :         TypeConstraint *constraint = types->constraintList;
    2977             154 :         while (constraint) {
    2978              98 :             constraint->newObjectState(cx, this, true);
    2979              98 :             constraint = constraint->next;
    2980                 :         }
    2981                 :     }
    2982                 : }
    2983                 : 
    2984                 : void
    2985          159376 : TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags)
    2986                 : {
    2987          159376 :     if ((this->flags & flags) == flags)
    2988             934 :         return;
    2989                 : 
    2990          316884 :     AutoEnterTypeInference enter(cx);
    2991                 : 
    2992          158442 :     if (singleton) {
    2993                 :         /* Make sure flags are consistent with persistent object state. */
    2994             650 :         JS_ASSERT_IF(flags & OBJECT_FLAG_CREATED_ARGUMENTS,
    2995                 :                      (flags & OBJECT_FLAG_UNINLINEABLE) &&
    2996            2973 :                      interpretedFunction->script()->createdArgs);
    2997            2218 :         JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE,
    2998            4541 :                      interpretedFunction->script()->uninlineable);
    2999              34 :         JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION,
    3000            2357 :                      interpretedFunction->script()->reentrantOuterFunction);
    3001              66 :         JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
    3002            2389 :                      singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
    3003                 :     }
    3004                 : 
    3005          158442 :     this->flags |= flags;
    3006                 : 
    3007          158442 :     InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
    3008                 : 
    3009          158442 :     ObjectStateChange(cx, this, false, false);
    3010                 : }
    3011                 : 
    3012                 : void
    3013           26120 : TypeObject::markUnknown(JSContext *cx)
    3014                 : {
    3015           52240 :     AutoEnterTypeInference enter(cx);
    3016                 : 
    3017           26120 :     JS_ASSERT(cx->compartment->activeInference);
    3018           26120 :     JS_ASSERT(!unknownProperties());
    3019                 : 
    3020           26120 :     if (!(flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED))
    3021           26115 :         clearNewScript(cx);
    3022                 : 
    3023           26120 :     InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this));
    3024                 : 
    3025           26120 :     ObjectStateChange(cx, this, true, true);
    3026                 : 
    3027                 :     /*
    3028                 :      * Existing constraints may have already been added to this object, which we need
    3029                 :      * to do the right thing for. We can't ensure that we will mark all unknown
    3030                 :      * objects before they have been accessed, as the __proto__ of a known object
    3031                 :      * could be dynamically set to an unknown object, and we can decide to ignore
    3032                 :      * properties of an object during analysis (i.e. hashmaps). Adding unknown for
    3033                 :      * any properties accessed already accounts for possible values read from them.
    3034                 :      */
    3035                 : 
    3036           26120 :     unsigned count = getPropertyCount();
    3037           27088 :     for (unsigned i = 0; i < count; i++) {
    3038             968 :         Property *prop = getProperty(i);
    3039             968 :         if (prop) {
    3040             664 :             prop->types.addType(cx, Type::UnknownType());
    3041             664 :             prop->types.setOwnProperty(cx, true);
    3042                 :         }
    3043                 :     }
    3044           26120 : }
    3045                 : 
    3046                 : void
    3047           26155 : TypeObject::clearNewScript(JSContext *cx)
    3048                 : {
    3049           26155 :     JS_ASSERT(!(flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED));
    3050           26155 :     flags |= OBJECT_FLAG_NEW_SCRIPT_CLEARED;
    3051                 : 
    3052                 :     /*
    3053                 :      * It is possible for the object to not have a new script yet but to have
    3054                 :      * one added in the future. When analyzing properties of new scripts we mix
    3055                 :      * in adding constraints to trigger clearNewScript with changes to the
    3056                 :      * type sets themselves (from breakTypeBarriers). It is possible that we
    3057                 :      * could trigger one of these constraints before AnalyzeNewScriptProperties
    3058                 :      * has finished, in which case we want to make sure that call fails.
    3059                 :      */
    3060           26155 :     if (!newScript)
    3061           26115 :         return;
    3062                 : 
    3063              80 :     AutoEnterTypeInference enter(cx);
    3064                 : 
    3065                 :     /*
    3066                 :      * Any definite properties we added due to analysis of the new script when
    3067                 :      * the type object was created are now invalid: objects with the same type
    3068                 :      * can be created by using 'new' on a different script or through some
    3069                 :      * other mechanism (e.g. Object.create). Rather than clear out the definite
    3070                 :      * bits on the object's properties, just mark such properties as having
    3071                 :      * been deleted/reconfigured, which will have the same effect on JITs
    3072                 :      * wanting to use the definite bits to optimize property accesses.
    3073                 :      */
    3074             140 :     for (unsigned i = 0; i < getPropertyCount(); i++) {
    3075             100 :         Property *prop = getProperty(i);
    3076             100 :         if (!prop)
    3077               0 :             continue;
    3078             100 :         if (prop->types.isDefiniteProperty())
    3079             100 :             prop->types.setOwnProperty(cx, true);
    3080                 :     }
    3081                 : 
    3082                 :     /*
    3083                 :      * If we cleared the new script while in the middle of initializing an
    3084                 :      * object, it will still have the new script's shape and reflect the no
    3085                 :      * longer correct state of the object once its initialization is completed.
    3086                 :      * We can't really detect the possibility of this statically, but the new
    3087                 :      * script keeps track of where each property is initialized so we can walk
    3088                 :      * the stack and fix up any such objects.
    3089                 :      */
    3090             130 :     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
    3091              90 :         StackFrame *fp = iter.fp();
    3092             175 :         if (fp->isScriptFrame() && fp->isConstructing() &&
    3093              45 :             fp->fun() == newScript->fun && fp->thisValue().isObject() &&
    3094              20 :             !fp->thisValue().toObject().hasLazyType() &&
    3095              20 :             fp->thisValue().toObject().type() == this) {
    3096              20 :             JSObject *obj = &fp->thisValue().toObject();
    3097              20 :             jsbytecode *pc = iter.pc();
    3098                 : 
    3099                 :             /* Whether all identified 'new' properties have been initialized. */
    3100              20 :             bool finished = false;
    3101                 : 
    3102                 :             /* If not finished, number of properties that have been added. */
    3103              20 :             uint32_t numProperties = 0;
    3104                 : 
    3105                 :             /*
    3106                 :              * If non-zero, we are scanning initializers in a call which has
    3107                 :              * already finished.
    3108                 :              */
    3109              20 :             size_t depth = 0;
    3110                 : 
    3111              70 :             for (TypeNewScript::Initializer *init = newScript->initializerList;; init++) {
    3112              70 :                 uint32_t offset = uint32_t(pc - fp->script()->code);
    3113              70 :                 if (init->kind == TypeNewScript::Initializer::SETPROP) {
    3114              50 :                     if (!depth && init->offset > offset) {
    3115                 :                         /* Advanced past all properties which have been initialized. */
    3116              15 :                         break;
    3117                 :                     }
    3118              35 :                     numProperties++;
    3119              20 :                 } else if (init->kind == TypeNewScript::Initializer::FRAME_PUSH) {
    3120              15 :                     if (depth) {
    3121               0 :                         depth++;
    3122              15 :                     } else if (init->offset > offset) {
    3123                 :                         /* Advanced past all properties which have been initialized. */
    3124               5 :                         break;
    3125              10 :                     } else if (init->offset == offset) {
    3126               5 :                         StackSegment &seg = cx->stack.space().containingSegment(fp);
    3127               5 :                         if (seg.maybefp() == fp)
    3128               0 :                             break;
    3129               5 :                         fp = seg.computeNextFrame(fp);
    3130               5 :                         pc = fp->pcQuadratic(cx->stack);
    3131                 :                     } else {
    3132                 :                         /* This call has already finished. */
    3133               5 :                         depth = 1;
    3134                 :                     }
    3135               5 :                 } else if (init->kind == TypeNewScript::Initializer::FRAME_POP) {
    3136               5 :                     if (depth) {
    3137               5 :                         depth--;
    3138                 :                     } else {
    3139                 :                         /* This call has not finished yet. */
    3140               0 :                         break;
    3141                 :                     }
    3142                 :                 } else {
    3143               0 :                     JS_ASSERT(init->kind == TypeNewScript::Initializer::DONE);
    3144               0 :                     finished = true;
    3145               0 :                     break;
    3146                 :                 }
    3147                 :             }
    3148                 : 
    3149              20 :             if (!finished)
    3150              20 :                 obj->rollbackProperties(cx, numProperties);
    3151                 :         }
    3152                 :     }
    3153                 : 
    3154                 :     /* We NULL out newScript *before* freeing it so the write barrier works. */
    3155              40 :     TypeNewScript *savedNewScript = newScript;
    3156              40 :     newScript = NULL;
    3157              40 :     cx->free_(savedNewScript);
    3158                 : 
    3159              40 :     markStateChange(cx);
    3160                 : }
    3161                 : 
    3162                 : void
    3163               0 : TypeObject::print(JSContext *cx)
    3164                 : {
    3165                 :     printf("%s : %s",
    3166                 :            TypeObjectString(this),
    3167               0 :            proto ? TypeString(Type::ObjectType(proto)) : "(null)");
    3168                 : 
    3169               0 :     if (unknownProperties()) {
    3170               0 :         printf(" unknown");
    3171                 :     } else {
    3172               0 :         if (!hasAnyFlags(OBJECT_FLAG_NON_PACKED_ARRAY))
    3173               0 :             printf(" packed");
    3174               0 :         if (!hasAnyFlags(OBJECT_FLAG_NON_DENSE_ARRAY))
    3175               0 :             printf(" dense");
    3176               0 :         if (!hasAnyFlags(OBJECT_FLAG_NON_TYPED_ARRAY))
    3177               0 :             printf(" typed");
    3178               0 :         if (hasAnyFlags(OBJECT_FLAG_UNINLINEABLE))
    3179               0 :             printf(" uninlineable");
    3180               0 :         if (hasAnyFlags(OBJECT_FLAG_SPECIAL_EQUALITY))
    3181               0 :             printf(" specialEquality");
    3182               0 :         if (hasAnyFlags(OBJECT_FLAG_ITERATED))
    3183               0 :             printf(" iterated");
    3184                 :     }
    3185                 : 
    3186               0 :     unsigned count = getPropertyCount();
    3187                 : 
    3188               0 :     if (count == 0) {
    3189               0 :         printf(" {}\n");
    3190               0 :         return;
    3191                 :     }
    3192                 : 
    3193               0 :     printf(" {");
    3194                 : 
    3195               0 :     for (unsigned i = 0; i < count; i++) {
    3196               0 :         Property *prop = getProperty(i);
    3197               0 :         if (prop) {
    3198               0 :             printf("\n    %s:", TypeIdString(prop->id));
    3199               0 :             prop->types.print(cx);
    3200                 :         }
    3201                 :     }
    3202                 : 
    3203               0 :     printf("\n}\n");
    3204                 : }
    3205                 : 
    3206                 : /////////////////////////////////////////////////////////////////////
    3207                 : // Type Analysis
    3208                 : /////////////////////////////////////////////////////////////////////
    3209                 : 
    3210                 : /*
    3211                 :  * If the bytecode immediately following code/pc is a test of the value
    3212                 :  * pushed by code, that value should be marked as possibly void.
    3213                 :  */
    3214                 : static inline bool
    3215          441363 : CheckNextTest(jsbytecode *pc)
    3216                 : {
    3217          441363 :     jsbytecode *next = pc + GetBytecodeLength(pc);
    3218          441363 :     switch ((JSOp)*next) {
    3219                 :       case JSOP_IFEQ:
    3220                 :       case JSOP_IFNE:
    3221                 :       case JSOP_NOT:
    3222                 :       case JSOP_OR:
    3223                 :       case JSOP_AND:
    3224                 :       case JSOP_TYPEOF:
    3225                 :       case JSOP_TYPEOFEXPR:
    3226             837 :         return true;
    3227                 :       default:
    3228                 :         /* TRAP ok here */
    3229          440526 :         return false;
    3230                 :     }
    3231                 : }
    3232                 : 
    3233                 : static inline TypeObject *
    3234           22758 : GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
    3235                 : {
    3236           22758 :     if (!script->hasGlobal())
    3237             706 :         return NULL;
    3238                 : 
    3239           22052 :     JSOp op = JSOp(*pc);
    3240           22052 :     JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
    3241                 : 
    3242           22052 :     bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
    3243           22052 :     return TypeScript::InitObject(cx, script, pc, isArray ? JSProto_Array : JSProto_Object);
    3244                 : }
    3245                 : 
    3246                 : /*
    3247                 :  * Detach nesting state for script from its parent, removing it entirely if it
    3248                 :  * has no children of its own. This happens when walking type information while
    3249                 :  * initially resolving NAME accesses, thus will not invalidate any compiler
    3250                 :  * dependencies.
    3251                 :  */
    3252                 : static void
    3253             186 : DetachNestingParent(JSScript *script)
    3254                 : {
    3255             186 :     TypeScriptNesting *nesting = script->nesting();
    3256                 : 
    3257             186 :     if (!nesting || !nesting->parent)
    3258               0 :         return;
    3259                 : 
    3260                 :     /* Remove from parent's list of children. */
    3261             186 :     JSScript **pscript = &nesting->parent->nesting()->children;
    3262             390 :     while ((*pscript)->nesting() != nesting)
    3263              18 :         pscript = &(*pscript)->nesting()->next;
    3264             186 :     *pscript = nesting->next;
    3265                 : 
    3266             186 :     nesting->parent = NULL;
    3267                 : 
    3268                 :     /* If this nesting can have no children of its own, destroy it. */
    3269             186 :     if (!script->isOuterFunction)
    3270             178 :         script->clearNesting();
    3271                 : }
    3272                 : 
    3273                 : ScriptAnalysis::NameAccess
    3274           67128 : ScriptAnalysis::resolveNameAccess(JSContext *cx, jsid id, bool addDependency)
    3275                 : {
    3276           67128 :     JS_ASSERT(cx->typeInferenceEnabled());
    3277                 : 
    3278                 :     NameAccess access;
    3279           67128 :     PodZero(&access);
    3280                 : 
    3281           67128 :     if (!JSID_IS_ATOM(id))
    3282               0 :         return access;
    3283           67128 :     JSAtom *atom = JSID_TO_ATOM(id);
    3284                 : 
    3285           67128 :     JSScript *script = this->script;
    3286          171226 :     while (script->function() && script->nesting()) {
    3287           73564 :         if (!script->ensureRanInference(cx))
    3288               0 :             return access;
    3289                 : 
    3290                 :         /*
    3291                 :          * Don't resolve names in scripts which use 'let' or 'with'. New names
    3292                 :          * bound here can mask variables of the script itself.
    3293                 :          *
    3294                 :          * Also, don't resolve names in scripts which are generators. Frame
    3295                 :          * balancing works differently for generators and we do not maintain
    3296                 :          * active frame counts for such scripts.
    3297                 :          */
    3298           73564 :         if (script->analysis()->addsScopeObjects() ||
    3299                 :             JSOp(*script->code) == JSOP_GENERATOR) {
    3300             119 :             return access;
    3301                 :         }
    3302                 : 
    3303                 :         /* Check if the script definitely binds the identifier. */
    3304                 :         unsigned index;
    3305           73445 :         BindingKind kind = script->bindings.lookup(cx, atom, &index);
    3306           73445 :         if (kind == ARGUMENT || kind == VARIABLE) {
    3307           35649 :             TypeObject *obj = script->function()->getType(cx);
    3308                 : 
    3309           35649 :             if (addDependency) {
    3310                 :                 /*
    3311                 :                  * Record the dependency which compiled code has on the outer
    3312                 :                  * function being non-reentrant.
    3313                 :                  */
    3314           29889 :                 if (TypeSet::HasObjectFlags(cx, obj, OBJECT_FLAG_REENTRANT_FUNCTION))
    3315             836 :                     return access;
    3316                 :             }
    3317                 : 
    3318           34813 :             if (!script->isOuterFunction)
    3319               0 :                 return access;
    3320                 : 
    3321           34813 :             access.script = script;
    3322           34813 :             access.nesting = script->nesting();
    3323           34813 :             access.slot = (kind == ARGUMENT) ? ArgSlot(index) : LocalSlot(script, index);
    3324           34813 :             access.arg = (kind == ARGUMENT);
    3325           34813 :             access.index = index;
    3326           34813 :             return access;
    3327           37796 :         } else if (kind != NONE) {
    3328               0 :             return access;
    3329                 :         }
    3330                 : 
    3331                 :         /*
    3332                 :          * The script's bindings do not contain a name for the function itself,
    3333                 :          * don't resolve name accesses on lambdas in DeclEnv objects on the
    3334                 :          * scope chain.
    3335                 :          */
    3336           37796 :         if (atom == CallObjectLambdaName(script->function()))
    3337              16 :             return access;
    3338                 : 
    3339           37780 :         if (!script->nesting()->parent)
    3340             810 :             return access;
    3341           36970 :         script = script->nesting()->parent;
    3342                 :     }
    3343                 : 
    3344           30534 :     return access;
    3345                 : }
    3346                 : 
    3347                 : /* Analyze type information for a single bytecode. */
    3348                 : bool
    3349         2007704 : ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
    3350                 :                                      TypeInferenceState &state)
    3351                 : {
    3352         2007704 :     jsbytecode *pc = script->code + offset;
    3353         2007704 :     JSOp op = (JSOp)*pc;
    3354                 : 
    3355         2007704 :     Bytecode &code = getCode(offset);
    3356         2007704 :     JS_ASSERT(!code.pushedTypes);
    3357                 : 
    3358         2007704 :     InferSpew(ISpewOps, "analyze: #%u:%05u", script->id(), offset);
    3359                 : 
    3360         2007704 :     unsigned defCount = GetDefCount(script, offset);
    3361         2007704 :     if (ExtendedDef(pc))
    3362          104406 :         defCount++;
    3363                 : 
    3364         2007704 :     TypeSet *pushed = cx->typeLifoAlloc().newArrayUninitialized<TypeSet>(defCount);
    3365         2007704 :     if (!pushed)
    3366               0 :         return false;
    3367         2007704 :     PodZero(pushed, defCount);
    3368         2007704 :     code.pushedTypes = pushed;
    3369                 : 
    3370                 :     /*
    3371                 :      * Add phi nodes introduced at this point to the list of all phi nodes in
    3372                 :      * the script. Types for these are not generated until after the script has
    3373                 :      * been processed, as types can flow backwards into phi nodes and the
    3374                 :      * source sets may not exist if we try to process these eagerly.
    3375                 :      */
    3376         2007704 :     if (code.newValues) {
    3377           16216 :         SlotValue *newv = code.newValues;
    3378           95953 :         while (newv->slot) {
    3379           63521 :             if (newv->value.kind() != SSAValue::PHI || newv->value.phiOffset() != offset) {
    3380           48611 :                 newv++;
    3381           48611 :                 continue;
    3382                 :             }
    3383                 : 
    3384                 :             /*
    3385                 :              * The phi nodes at join points should all be unique, and every phi
    3386                 :              * node created should be in the phiValues list on some bytecode.
    3387                 :              */
    3388           14910 :             if (!state.phiNodes.append(newv->value.phiNode()))
    3389               0 :                 return false;
    3390           14910 :             TypeSet &types = newv->value.phiNode()->types;
    3391                 :             InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u",
    3392                 :                       InferSpewColor(&types), &types, InferSpewColorReset(),
    3393           14910 :                       script->id(), offset, newv->slot);
    3394           14910 :             newv++;
    3395                 :         }
    3396                 :     }
    3397                 : 
    3398                 :     /*
    3399                 :      * Treat decomposed ops as no-ops, we will analyze the decomposed version
    3400                 :      * instead. (We do, however, need to look at introduced phi nodes).
    3401                 :      */
    3402         2007704 :     if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
    3403            3660 :         return true;
    3404                 : 
    3405         3782814 :     for (unsigned i = 0; i < defCount; i++) {
    3406                 :         InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u",
    3407                 :                   InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(),
    3408         1778770 :                   i, script->id(), offset);
    3409                 :     }
    3410                 : 
    3411                 :     /* Add type constraints for the various opcodes. */
    3412         2004044 :     switch (op) {
    3413                 : 
    3414                 :         /* Nop bytecodes. */
    3415                 :       case JSOP_POP:
    3416                 :       case JSOP_NOP:
    3417                 :       case JSOP_LOOPHEAD:
    3418                 :       case JSOP_LOOPENTRY:
    3419                 :       case JSOP_GOTO:
    3420                 :       case JSOP_IFEQ:
    3421                 :       case JSOP_IFNE:
    3422                 :       case JSOP_LINENO:
    3423                 :       case JSOP_DEFCONST:
    3424                 :       case JSOP_LEAVEWITH:
    3425                 :       case JSOP_LEAVEBLOCK:
    3426                 :       case JSOP_RETRVAL:
    3427                 :       case JSOP_ENDITER:
    3428                 :       case JSOP_THROWING:
    3429                 :       case JSOP_GOSUB:
    3430                 :       case JSOP_RETSUB:
    3431                 :       case JSOP_CONDSWITCH:
    3432                 :       case JSOP_DEFAULT:
    3433                 :       case JSOP_POPN:
    3434                 :       case JSOP_STARTXML:
    3435                 :       case JSOP_STARTXMLEXPR:
    3436                 :       case JSOP_DEFXMLNS:
    3437                 :       case JSOP_POPV:
    3438                 :       case JSOP_DEBUGGER:
    3439                 :       case JSOP_SETCALL:
    3440                 :       case JSOP_TABLESWITCH:
    3441                 :       case JSOP_LOOKUPSWITCH:
    3442                 :       case JSOP_TRY:
    3443                 :       case JSOP_LABEL:
    3444          362432 :         break;
    3445                 : 
    3446                 :         /* Bytecodes pushing values of known type. */
    3447                 :       case JSOP_VOID:
    3448                 :       case JSOP_UNDEFINED:
    3449           73867 :         pushed[0].addType(cx, Type::UndefinedType());
    3450           73867 :         break;
    3451                 :       case JSOP_ZERO:
    3452                 :       case JSOP_ONE:
    3453                 :       case JSOP_INT8:
    3454                 :       case JSOP_INT32:
    3455                 :       case JSOP_UINT16:
    3456                 :       case JSOP_UINT24:
    3457                 :       case JSOP_BITAND:
    3458                 :       case JSOP_BITOR:
    3459                 :       case JSOP_BITXOR:
    3460                 :       case JSOP_BITNOT:
    3461                 :       case JSOP_RSH:
    3462                 :       case JSOP_LSH:
    3463                 :       case JSOP_URSH:
    3464          112884 :         pushed[0].addType(cx, Type::Int32Type());
    3465          112884 :         break;
    3466                 :       case JSOP_FALSE:
    3467                 :       case JSOP_TRUE:
    3468                 :       case JSOP_EQ:
    3469                 :       case JSOP_NE:
    3470                 :       case JSOP_LT:
    3471                 :       case JSOP_LE:
    3472                 :       case JSOP_GT:
    3473                 :       case JSOP_GE:
    3474                 :       case JSOP_NOT:
    3475                 :       case JSOP_STRICTEQ:
    3476                 :       case JSOP_STRICTNE:
    3477                 :       case JSOP_IN:
    3478                 :       case JSOP_INSTANCEOF:
    3479                 :       case JSOP_DELDESC:
    3480           38057 :         pushed[0].addType(cx, Type::BooleanType());
    3481           38057 :         break;
    3482                 :       case JSOP_DOUBLE:
    3483            2611 :         pushed[0].addType(cx, Type::DoubleType());
    3484            2611 :         break;
    3485                 :       case JSOP_STRING:
    3486                 :       case JSOP_TYPEOF:
    3487                 :       case JSOP_TYPEOFEXPR:
    3488                 :       case JSOP_QNAMEPART:
    3489                 :       case JSOP_XMLTAGEXPR:
    3490                 :       case JSOP_TOATTRVAL:
    3491                 :       case JSOP_ADDATTRNAME:
    3492                 :       case JSOP_ADDATTRVAL:
    3493                 :       case JSOP_XMLELTEXPR:
    3494           50126 :         pushed[0].addType(cx, Type::StringType());
    3495           50126 :         break;
    3496                 :       case JSOP_NULL:
    3497            3263 :         pushed[0].addType(cx, Type::NullType());
    3498            3263 :         break;
    3499                 : 
    3500                 :       case JSOP_REGEXP:
    3501            1365 :         if (script->hasGlobal()) {
    3502            1361 :             TypeObject *object = TypeScript::StandardType(cx, script, JSProto_RegExp);
    3503            1361 :             if (!object)
    3504               0 :                 return false;
    3505            1361 :             pushed[0].addType(cx, Type::ObjectType(object));
    3506                 :         } else {
    3507               4 :             pushed[0].addType(cx, Type::UnknownType());
    3508                 :         }
    3509            1365 :         break;
    3510                 : 
    3511                 :       case JSOP_OBJECT: {
    3512            1078 :         JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
    3513            1078 :         pushed[0].addType(cx, Type::ObjectType(obj));
    3514            1078 :         break;
    3515                 :       }
    3516                 : 
    3517                 :       case JSOP_STOP:
    3518                 :         /* If a stop is reachable then the return type may be void. */
    3519           32160 :           if (script->function())
    3520           10223 :             TypeScript::ReturnTypes(script)->addType(cx, Type::UndefinedType());
    3521           32160 :         break;
    3522                 : 
    3523                 :       case JSOP_OR:
    3524                 :       case JSOP_AND:
    3525                 :         /* OR/AND push whichever operand determined the result. */
    3526            1344 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3527            1344 :         break;
    3528                 : 
    3529                 :       case JSOP_DUP:
    3530           20712 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3531           20712 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[1]);
    3532           20712 :         break;
    3533                 : 
    3534                 :       case JSOP_DUP2:
    3535             296 :         poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
    3536             296 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[1]);
    3537             296 :         poppedTypes(pc, 1)->addSubset(cx, &pushed[2]);
    3538             296 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[3]);
    3539             296 :         break;
    3540                 : 
    3541                 :       case JSOP_SWAP:
    3542                 :       case JSOP_PICK: {
    3543           21662 :         unsigned pickedDepth = (op == JSOP_SWAP ? 1 : GET_UINT8(pc));
    3544                 :         /* The last popped value is the last pushed. */
    3545           21662 :         poppedTypes(pc, pickedDepth)->addSubset(cx, &pushed[pickedDepth]);
    3546           46452 :         for (unsigned i = 0; i < pickedDepth; i++)
    3547           24790 :             poppedTypes(pc, i)->addSubset(cx, &pushed[pickedDepth - 1 - i]);
    3548           21662 :         break;
    3549                 :       }
    3550                 : 
    3551                 :       case JSOP_GETGNAME:
    3552                 :       case JSOP_CALLGNAME: {
    3553          397847 :         jsid id = GetAtomId(cx, script, pc, 0);
    3554                 : 
    3555          397847 :         TypeSet *seen = bytecodeTypes(pc);
    3556          397847 :         seen->addSubset(cx, &pushed[0]);
    3557                 : 
    3558                 :         /*
    3559                 :          * Normally we rely on lazy standard class initialization to fill in
    3560                 :          * the types of global properties the script can access. In a few cases
    3561                 :          * the method JIT will bypass this, and we need to add the types direclty.
    3562                 :          */
    3563          397847 :         if (id == ATOM_TO_JSID(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]))
    3564            1301 :             seen->addType(cx, Type::UndefinedType());
    3565          397847 :         if (id == ATOM_TO_JSID(cx->runtime->atomState.NaNAtom))
    3566             346 :             seen->addType(cx, Type::DoubleType());
    3567          397847 :         if (id == ATOM_TO_JSID(cx->runtime->atomState.InfinityAtom))
    3568             216 :             seen->addType(cx, Type::DoubleType());
    3569                 : 
    3570                 :         /* Handle as a property access. */
    3571          397847 :         PropertyAccess(cx, script, pc, script->global()->getType(cx), false, seen, id);
    3572                 : 
    3573          397847 :         if (op == JSOP_CALLGNAME)
    3574           26503 :             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
    3575                 : 
    3576          397847 :         if (CheckNextTest(pc))
    3577             418 :             pushed[0].addType(cx, Type::UndefinedType());
    3578          397847 :         break;
    3579                 :       }
    3580                 : 
    3581                 :       case JSOP_NAME:
    3582                 :       case JSOP_CALLNAME: {
    3583           13911 :         TypeSet *seen = bytecodeTypes(pc);
    3584           13911 :         seen->addSubset(cx, &pushed[0]);
    3585                 : 
    3586                 :         /*
    3587                 :          * Try to resolve this name by walking the function's scope nesting.
    3588                 :          * If we succeed but the accessed script has had its TypeScript purged
    3589                 :          * in the past, we still must use a type barrier: the name access can
    3590                 :          * be on a call object which predated the purge, and whose types might
    3591                 :          * not be reflected in the reconstructed information.
    3592                 :          */
    3593           13911 :         jsid id = GetAtomId(cx, script, pc, 0);
    3594           13911 :         NameAccess access = resolveNameAccess(cx, id);
    3595           13911 :         if (access.script && !access.script->typesPurged) {
    3596            5412 :             TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
    3597            5412 :             types->addSubsetBarrier(cx, script, pc, seen);
    3598                 :         } else {
    3599            8499 :             addTypeBarrier(cx, pc, seen, Type::UnknownType());
    3600                 :         }
    3601                 : 
    3602           13911 :         if (op == JSOP_CALLNAME)
    3603            2675 :             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
    3604           13911 :         break;
    3605                 :       }
    3606                 : 
    3607                 :       case JSOP_BINDGNAME:
    3608                 :       case JSOP_BINDNAME:
    3609           30788 :         break;
    3610                 : 
    3611                 :       case JSOP_SETGNAME: {
    3612           29390 :         jsid id = GetAtomId(cx, script, pc, 0);
    3613           29390 :         PropertyAccess(cx, script, pc, script->global()->getType(cx),
    3614           58780 :                        true, poppedTypes(pc, 0), id);
    3615           29390 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3616           29390 :         break;
    3617                 :       }
    3618                 : 
    3619                 :       case JSOP_SETNAME: {
    3620            1344 :         jsid id = GetAtomId(cx, script, pc, 0);
    3621            1344 :         NameAccess access = resolveNameAccess(cx, id);
    3622            1344 :         if (access.script) {
    3623             348 :             TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
    3624             348 :             poppedTypes(pc, 0)->addSubset(cx, types);
    3625                 :         } else {
    3626             996 :             cx->compartment->types.monitorBytecode(cx, script, offset);
    3627                 :         }
    3628            1344 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3629            1344 :         break;
    3630                 :       }
    3631                 : 
    3632                 :       case JSOP_SETCONST:
    3633            8314 :         cx->compartment->types.monitorBytecode(cx, script, offset);
    3634            8314 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3635            8314 :         break;
    3636                 : 
    3637                 :       case JSOP_GETXPROP:
    3638                 :       case JSOP_GETFCSLOT:
    3639                 :       case JSOP_CALLFCSLOT: {
    3640             556 :         TypeSet *seen = bytecodeTypes(pc);
    3641             556 :         addTypeBarrier(cx, pc, seen, Type::UnknownType());
    3642             556 :         seen->addSubset(cx, &pushed[0]);
    3643             556 :         if (op == JSOP_CALLFCSLOT)
    3644              78 :             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
    3645             556 :         break;
    3646                 :       }
    3647                 : 
    3648                 :       case JSOP_GETARG:
    3649                 :       case JSOP_CALLARG:
    3650                 :       case JSOP_GETLOCAL:
    3651                 :       case JSOP_CALLLOCAL: {
    3652          119452 :         uint32_t slot = GetBytecodeSlot(script, pc);
    3653          119452 :         if (trackSlot(slot)) {
    3654                 :             /*
    3655                 :              * Normally these opcodes don't pop anything, but they are given
    3656                 :              * an extended use holding the variable's SSA value before the
    3657                 :              * access. Use the types from here.
    3658                 :              */
    3659           39550 :             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3660           79902 :         } else if (slot < TotalSlots(script)) {
    3661           60142 :             TypeSet *types = TypeScript::SlotTypes(script, slot);
    3662           60142 :             types->addSubset(cx, &pushed[0]);
    3663                 :         } else {
    3664                 :             /* Local 'let' variable. Punt on types for these, for now. */
    3665           19760 :             pushed[0].addType(cx, Type::UnknownType());
    3666                 :         }
    3667          119452 :         if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
    3668            1690 :             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
    3669          119452 :         break;
    3670                 :       }
    3671                 : 
    3672                 :       case JSOP_SETARG:
    3673                 :       case JSOP_SETLOCAL:
    3674                 :       case JSOP_SETLOCALPOP: {
    3675           97059 :         uint32_t slot = GetBytecodeSlot(script, pc);
    3676           97059 :         if (!trackSlot(slot) && slot < TotalSlots(script)) {
    3677           41826 :             TypeSet *types = TypeScript::SlotTypes(script, slot);
    3678           41826 :             poppedTypes(pc, 0)->addSubset(cx, types);
    3679                 :         }
    3680                 : 
    3681                 :         /*
    3682                 :          * For assignments to non-escaping locals/args, we don't need to update
    3683                 :          * the possible types of the var, as for each read of the var SSA gives
    3684                 :          * us the writes that could have produced that read.
    3685                 :          */
    3686           97059 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3687           97059 :         break;
    3688                 :       }
    3689                 : 
    3690                 :       case JSOP_INCARG:
    3691                 :       case JSOP_DECARG:
    3692                 :       case JSOP_ARGINC:
    3693                 :       case JSOP_ARGDEC:
    3694                 :       case JSOP_INCLOCAL:
    3695                 :       case JSOP_DECLOCAL:
    3696                 :       case JSOP_LOCALINC:
    3697                 :       case JSOP_LOCALDEC: {
    3698            6402 :         uint32_t slot = GetBytecodeSlot(script, pc);
    3699            6402 :         if (trackSlot(slot)) {
    3700            2553 :             poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
    3701            3849 :         } else if (slot < TotalSlots(script)) {
    3702            2693 :             TypeSet *types = TypeScript::SlotTypes(script, slot);
    3703            2693 :             types->addArith(cx, script, pc, types);
    3704            2693 :             types->addSubset(cx, &pushed[0]);
    3705                 :         } else {
    3706            1156 :             pushed[0].addType(cx, Type::UnknownType());
    3707                 :         }
    3708            6402 :         break;
    3709                 :       }
    3710                 : 
    3711                 :       case JSOP_ARGUMENTS: {
    3712                 :         /* Compute a precise type only when we know the arguments won't escape. */
    3713            1774 :         TypeObject *funType = script->function()->getType(cx);
    3714            1774 :         if (funType->unknownProperties() || funType->hasAnyFlags(OBJECT_FLAG_CREATED_ARGUMENTS)) {
    3715              16 :             pushed[0].addType(cx, Type::UnknownType());
    3716              16 :             break;
    3717                 :         }
    3718            1758 :         TypeSet *types = funType->getProperty(cx, JSID_EMPTY, false);
    3719            1758 :         if (!types)
    3720               0 :             break;
    3721            1758 :         types->addLazyArguments(cx, &pushed[0]);
    3722            1758 :         pushed[0].addType(cx, Type::LazyArgsType());
    3723            1758 :         break;
    3724                 :       }
    3725                 : 
    3726                 :       case JSOP_SETPROP:
    3727                 :       case JSOP_SETMETHOD: {
    3728            5546 :         jsid id = GetAtomId(cx, script, pc, 0);
    3729            5546 :         poppedTypes(pc, 1)->addSetProperty(cx, script, pc, poppedTypes(pc, 0), id);
    3730            5546 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3731            5546 :         break;
    3732                 :       }
    3733                 : 
    3734                 :       case JSOP_LENGTH:
    3735                 :       case JSOP_GETPROP:
    3736                 :       case JSOP_CALLPROP: {
    3737           32181 :         jsid id = GetAtomId(cx, script, pc, 0);
    3738           32181 :         TypeSet *seen = script->analysis()->bytecodeTypes(pc);
    3739                 : 
    3740           32181 :         poppedTypes(pc, 0)->addGetProperty(cx, script, pc, seen, id);
    3741           32181 :         if (op == JSOP_CALLPROP)
    3742           16023 :             poppedTypes(pc, 0)->addCallProperty(cx, script, pc, id);
    3743                 : 
    3744           32181 :         seen->addSubset(cx, &pushed[0]);
    3745           32181 :         if (CheckNextTest(pc))
    3746             229 :             pushed[0].addType(cx, Type::UndefinedType());
    3747           32181 :         break;
    3748                 :       }
    3749                 : 
    3750                 :       /*
    3751                 :        * We only consider ELEM accesses on integers below. Any element access
    3752                 :        * which is accessing a non-integer property must be monitored.
    3753                 :        */
    3754                 : 
    3755                 :       case JSOP_GETELEM:
    3756                 :       case JSOP_CALLELEM: {
    3757           11335 :         TypeSet *seen = script->analysis()->bytecodeTypes(pc);
    3758                 : 
    3759           11335 :         poppedTypes(pc, 1)->addGetProperty(cx, script, pc, seen, JSID_VOID);
    3760                 : 
    3761           11335 :         seen->addSubset(cx, &pushed[0]);
    3762           11335 :         if (op == JSOP_CALLELEM)
    3763             141 :             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType(), poppedTypes(pc, 1));
    3764           11335 :         if (CheckNextTest(pc))
    3765             190 :             pushed[0].addType(cx, Type::UndefinedType());
    3766           11335 :         break;
    3767                 :       }
    3768                 : 
    3769                 :       case JSOP_SETELEM:
    3770            4338 :         poppedTypes(pc, 1)->addSetElement(cx, script, pc, poppedTypes(pc, 2), poppedTypes(pc, 0));
    3771            4338 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    3772            4338 :         break;
    3773                 : 
    3774                 :       case JSOP_TOID:
    3775                 :         /*
    3776                 :          * This is only used for element inc/dec ops; any id produced which
    3777                 :          * is not an integer must be monitored.
    3778                 :          */
    3779             152 :         pushed[0].addType(cx, Type::Int32Type());
    3780             152 :         break;
    3781                 : 
    3782                 :       case JSOP_THIS:
    3783           13069 :         TypeScript::ThisTypes(script)->addTransformThis(cx, script, &pushed[0]);
    3784           13069 :         break;
    3785                 : 
    3786                 :       case JSOP_RETURN:
    3787                 :       case JSOP_SETRVAL:
    3788            7844 :           if (script->function())
    3789            7844 :             poppedTypes(pc, 0)->addSubset(cx, TypeScript::ReturnTypes(script));
    3790            7844 :         break;
    3791                 : 
    3792                 :       case JSOP_ADD:
    3793          340891 :         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 1));
    3794          340891 :         poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 0));
    3795          340891 :         break;
    3796                 : 
    3797                 :       case JSOP_SUB:
    3798                 :       case JSOP_MUL:
    3799                 :       case JSOP_MOD:
    3800                 :       case JSOP_DIV:
    3801            4162 :         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
    3802            4162 :         poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0]);
    3803            4162 :         break;
    3804                 : 
    3805                 :       case JSOP_NEG:
    3806                 :       case JSOP_POS:
    3807            5017 :         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
    3808            5017 :         break;
    3809                 : 
    3810                 :       case JSOP_LAMBDA:
    3811                 :       case JSOP_LAMBDA_FC:
    3812                 :       case JSOP_DEFFUN:
    3813                 :       case JSOP_DEFLOCALFUN:
    3814                 :       case JSOP_DEFLOCALFUN_FC: {
    3815           21850 :         unsigned off = (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) ? SLOTNO_LEN : 0;
    3816           21850 :         JSObject *obj = script->getObject(GET_UINT32_INDEX(pc + off));
    3817                 : 
    3818           21850 :         TypeSet *res = NULL;
    3819           21850 :         if (op == JSOP_LAMBDA || op == JSOP_LAMBDA_FC) {
    3820           20199 :             res = &pushed[0];
    3821            1651 :         } else if (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) {
    3822             945 :             uint32_t slot = GetBytecodeSlot(script, pc);
    3823             945 :             if (trackSlot(slot)) {
    3824             265 :                 res = &pushed[0];
    3825                 :             } else {
    3826                 :                 /* Should not see 'let' vars here. */
    3827             680 :                 JS_ASSERT(slot < TotalSlots(script));
    3828             680 :                 res = TypeScript::SlotTypes(script, slot);
    3829                 :             }
    3830                 :         }
    3831                 : 
    3832           21850 :         if (res) {
    3833           21144 :             if (script->hasGlobal())
    3834           21092 :                 res->addType(cx, Type::ObjectType(obj));
    3835                 :             else
    3836              52 :                 res->addType(cx, Type::UnknownType());
    3837                 :         } else {
    3838             706 :             cx->compartment->types.monitorBytecode(cx, script, offset);
    3839                 :         }
    3840           21850 :         break;
    3841                 :       }
    3842                 : 
    3843                 :       case JSOP_DEFVAR:
    3844             826 :         break;
    3845                 : 
    3846                 :       case JSOP_CALL:
    3847                 :       case JSOP_EVAL:
    3848                 :       case JSOP_FUNCALL:
    3849                 :       case JSOP_FUNAPPLY:
    3850                 :       case JSOP_NEW: {
    3851           56863 :         TypeSet *seen = script->analysis()->bytecodeTypes(pc);
    3852           56863 :         seen->addSubset(cx, &pushed[0]);
    3853                 : 
    3854                 :         /* Construct the base call information about this site. */
    3855           56863 :         unsigned argCount = GetUseCount(script, offset) - 2;
    3856           56863 :         TypeCallsite *callsite = cx->typeLifoAlloc().new_<TypeCallsite>(
    3857          113726 :                                                         cx, script, pc, op == JSOP_NEW, argCount);
    3858           56863 :         if (!callsite || (argCount && !callsite->argumentTypes)) {
    3859               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    3860               0 :             break;
    3861                 :         }
    3862           56863 :         callsite->thisTypes = poppedTypes(pc, argCount);
    3863           56863 :         callsite->returnTypes = seen;
    3864                 : 
    3865          137563 :         for (unsigned i = 0; i < argCount; i++)
    3866           80700 :             callsite->argumentTypes[i] = poppedTypes(pc, argCount - 1 - i);
    3867                 : 
    3868                 :         /*
    3869                 :          * Mark FUNCALL and FUNAPPLY sites as monitored. The method JIT may
    3870                 :          * lower these into normal calls, and we need to make sure the
    3871                 :          * callee's argument types are checked on entry.
    3872                 :          */
    3873           56863 :         if (op == JSOP_FUNCALL || op == JSOP_FUNAPPLY)
    3874             903 :             cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
    3875                 : 
    3876           56863 :         poppedTypes(pc, argCount + 1)->addCall(cx, callsite);
    3877           56863 :         break;
    3878                 :       }
    3879                 : 
    3880                 :       case JSOP_NEWINIT:
    3881                 :       case JSOP_NEWARRAY:
    3882                 :       case JSOP_NEWOBJECT: {
    3883            6660 :         TypeObject *initializer = GetInitializerType(cx, script, pc);
    3884            6660 :         TypeSet *types = script->analysis()->bytecodeTypes(pc);
    3885            6660 :         if (script->hasGlobal()) {
    3886            6386 :             if (!initializer)
    3887               0 :                 return false;
    3888            6386 :             types->addType(cx, Type::ObjectType(initializer));
    3889                 :         } else {
    3890             274 :             JS_ASSERT(!initializer);
    3891             274 :             types->addType(cx, Type::UnknownType());
    3892                 :         }
    3893            6660 :         types->addSubset(cx, &pushed[0]);
    3894            6660 :         break;
    3895                 :       }
    3896                 : 
    3897                 :       case JSOP_ENDINIT:
    3898            6660 :         break;
    3899                 : 
    3900                 :       case JSOP_INITELEM: {
    3901           11160 :         const SSAValue &objv = poppedValue(pc, 2);
    3902           11160 :         jsbytecode *initpc = script->code + objv.pushedOffset();
    3903           11160 :         TypeObject *initializer = GetInitializerType(cx, script, initpc);
    3904                 : 
    3905           11160 :         if (initializer) {
    3906           10746 :             pushed[0].addType(cx, Type::ObjectType(initializer));
    3907           10746 :             if (!initializer->unknownProperties()) {
    3908                 :                 /*
    3909                 :                  * Assume the initialized element is an integer. INITELEM can be used
    3910                 :                  * for doubles which don't map to the JSID_VOID property, which must
    3911                 :                  * be caught with dynamic monitoring.
    3912                 :                  */
    3913           10734 :                 TypeSet *types = initializer->getProperty(cx, JSID_VOID, true);
    3914           10734 :                 if (!types)
    3915               0 :                     return false;
    3916           10734 :                 if (state.hasGetSet) {
    3917               0 :                     types->addType(cx, Type::UnknownType());
    3918           10734 :                 } else if (state.hasHole) {
    3919            1044 :                     if (!initializer->unknownProperties())
    3920            1044 :                         initializer->setFlags(cx, OBJECT_FLAG_NON_PACKED_ARRAY);
    3921                 :                 } else {
    3922            9690 :                     poppedTypes(pc, 0)->addSubset(cx, types);
    3923                 :                 }
    3924                 :             }
    3925                 :         } else {
    3926             414 :             pushed[0].addType(cx, Type::UnknownType());
    3927                 :         }
    3928           11160 :         state.hasGetSet = false;
    3929           11160 :         state.hasHole = false;
    3930           11160 :         break;
    3931                 :       }
    3932                 : 
    3933                 :       case JSOP_GETTER:
    3934                 :       case JSOP_SETTER:
    3935              66 :         state.hasGetSet = true;
    3936              66 :         break;
    3937                 : 
    3938                 :       case JSOP_HOLE:
    3939            1062 :         state.hasHole = true;
    3940            1062 :         break;
    3941                 : 
    3942                 :       case JSOP_INITPROP:
    3943                 :       case JSOP_INITMETHOD: {
    3944            4938 :         const SSAValue &objv = poppedValue(pc, 1);
    3945            4938 :         jsbytecode *initpc = script->code + objv.pushedOffset();
    3946            4938 :         TypeObject *initializer = GetInitializerType(cx, script, initpc);
    3947                 : 
    3948            4938 :         if (initializer) {
    3949            4920 :             pushed[0].addType(cx, Type::ObjectType(initializer));
    3950            4920 :             if (!initializer->unknownProperties()) {
    3951            4920 :                 jsid id = GetAtomId(cx, script, pc, 0);
    3952            4920 :                 TypeSet *types = initializer->getProperty(cx, id, true);
    3953            4920 :                 if (!types)
    3954               0 :                     return false;
    3955            4920 :                 if (id == id___proto__(cx) || id == id_prototype(cx))
    3956              14 :                     cx->compartment->types.monitorBytecode(cx, script, offset);
    3957            4906 :                 else if (state.hasGetSet)
    3958              66 :                     types->addType(cx, Type::UnknownType());
    3959                 :                 else
    3960            4840 :                     poppedTypes(pc, 0)->addSubset(cx, types);
    3961                 :             }
    3962                 :         } else {
    3963              18 :             pushed[0].addType(cx, Type::UnknownType());
    3964                 :         }
    3965            4938 :         state.hasGetSet = false;
    3966            4938 :         JS_ASSERT(!state.hasHole);
    3967            4938 :         break;
    3968                 :       }
    3969                 : 
    3970                 :       case JSOP_ENTERWITH:
    3971                 :       case JSOP_ENTERBLOCK:
    3972                 :       case JSOP_ENTERLET0:
    3973                 :         /*
    3974                 :          * Scope lookups can occur on the values being pushed here. We don't track
    3975                 :          * the value or its properties, and just monitor all name opcodes in the
    3976                 :          * script.
    3977                 :          */
    3978           17168 :         break;
    3979                 : 
    3980                 :       case JSOP_ENTERLET1:
    3981                 :         /*
    3982                 :          * JSOP_ENTERLET1 enters a let block with an unrelated value on top of
    3983                 :          * the stack (such as the condition to a switch) whose constraints must
    3984                 :          * be propagated. The other values are ignored for the same reason as
    3985                 :          * JSOP_ENTERLET0.
    3986                 :          */
    3987             215 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[defCount - 1]);
    3988             215 :         break;
    3989                 : 
    3990                 :       case JSOP_ITER: {
    3991                 :         /*
    3992                 :          * Use a per-script type set to unify the possible target types of all
    3993                 :          * 'for in' or 'for each' loops in the script. We need to mark the
    3994                 :          * value pushed by the ITERNEXT appropriately, but don't track the SSA
    3995                 :          * information to connect that ITERNEXT with the appropriate ITER.
    3996                 :          * This loses some precision when a script mixes 'for in' and
    3997                 :          * 'for each' loops together, oh well.
    3998                 :          */
    3999            1643 :         if (!state.forTypes) {
    4000            1194 :           state.forTypes = TypeSet::make(cx, "forTypes");
    4001            1194 :           if (!state.forTypes)
    4002               0 :               return false;
    4003                 :         }
    4004                 : 
    4005            1643 :         if (GET_UINT8(pc) & JSITER_FOREACH)
    4006             288 :             state.forTypes->addType(cx, Type::UnknownType());
    4007                 :         else
    4008            1355 :             state.forTypes->addType(cx, Type::StringType());
    4009            1643 :         break;
    4010                 :       }
    4011                 : 
    4012                 :       case JSOP_ITERNEXT:
    4013            1643 :         state.forTypes->addSubset(cx, &pushed[0]);
    4014            1643 :         break;
    4015                 : 
    4016                 :       case JSOP_MOREITER:
    4017            1643 :         pushed[1].addType(cx, Type::BooleanType());
    4018            1643 :         break;
    4019                 : 
    4020                 :       case JSOP_ENUMELEM:
    4021                 :       case JSOP_ENUMCONSTELEM:
    4022                 :       case JSOP_ARRAYPUSH:
    4023             106 :         cx->compartment->types.monitorBytecode(cx, script, offset);
    4024             106 :         break;
    4025                 : 
    4026                 :       case JSOP_THROW:
    4027                 :         /* There will be a monitor on the bytecode catching the exception. */
    4028             505 :         break;
    4029                 : 
    4030                 :       case JSOP_FINALLY:
    4031                 :         /* Pushes information about whether an exception was thrown. */
    4032              35 :         break;
    4033                 : 
    4034                 :       case JSOP_IMPLICITTHIS:
    4035                 :       case JSOP_EXCEPTION:
    4036           16378 :         pushed[0].addType(cx, Type::UnknownType());
    4037           16378 :         break;
    4038                 : 
    4039                 :       case JSOP_DELPROP:
    4040                 :       case JSOP_DELELEM:
    4041                 :       case JSOP_DELNAME:
    4042             359 :         pushed[0].addType(cx, Type::BooleanType());
    4043             359 :         break;
    4044                 : 
    4045                 :       case JSOP_LEAVEBLOCKEXPR:
    4046             188 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    4047             188 :         break;
    4048                 : 
    4049                 :       case JSOP_LEAVEFORLETIN:
    4050             233 :         break;
    4051                 : 
    4052                 :       case JSOP_CASE:
    4053              74 :         poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
    4054              74 :         break;
    4055                 : 
    4056                 :       case JSOP_GENERATOR:
    4057             148 :           if (script->function()) {
    4058             148 :             if (script->hasGlobal()) {
    4059             136 :                 JSObject *proto = script->global()->getOrCreateGeneratorPrototype(cx);
    4060             136 :                 if (!proto)
    4061               0 :                     return false;
    4062             136 :                 TypeObject *object = proto->getNewType(cx);
    4063             136 :                 if (!object)
    4064               0 :                     return false;
    4065             136 :                 TypeScript::ReturnTypes(script)->addType(cx, Type::ObjectType(object));
    4066                 :             } else {
    4067              12 :                 TypeScript::ReturnTypes(script)->addType(cx, Type::UnknownType());
    4068                 :             }
    4069                 :         }
    4070             148 :         break;
    4071                 : 
    4072                 :       case JSOP_YIELD:
    4073             156 :         pushed[0].addType(cx, Type::UnknownType());
    4074             156 :         break;
    4075                 : 
    4076                 :       case JSOP_CALLXMLNAME:
    4077               0 :         pushed[1].addType(cx, Type::UnknownType());
    4078                 :         /* FALLTHROUGH */
    4079                 : 
    4080                 :       case JSOP_XMLNAME:
    4081              11 :         pushed[0].addType(cx, Type::UnknownType());
    4082              11 :         break;
    4083                 : 
    4084                 :       case JSOP_SETXMLNAME:
    4085               4 :         cx->compartment->types.monitorBytecode(cx, script, offset);
    4086               4 :         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
    4087               4 :         break;
    4088                 : 
    4089                 :       case JSOP_BINDXMLNAME:
    4090               4 :         break;
    4091                 : 
    4092                 :       case JSOP_TOXML:
    4093                 :       case JSOP_TOXMLLIST:
    4094                 :       case JSOP_XMLPI:
    4095                 :       case JSOP_XMLCDATA:
    4096                 :       case JSOP_XMLCOMMENT:
    4097                 :       case JSOP_DESCENDANTS:
    4098                 :       case JSOP_TOATTRNAME:
    4099                 :       case JSOP_QNAMECONST:
    4100                 :       case JSOP_QNAME:
    4101                 :       case JSOP_ANYNAME:
    4102                 :       case JSOP_GETFUNNS:
    4103                 :       case JSOP_FILTER:
    4104                 :         /* Note: the second value pushed by filter is a hole, and not modelled. */
    4105                 :       case JSOP_ENDFILTER:
    4106             130 :         pushed[0].addType(cx, Type::UnknownType());
    4107             130 :         break;
    4108                 : 
    4109                 :       case JSOP_CALLEE:
    4110              87 :         if (script->hasGlobal())
    4111              71 :             pushed[0].addType(cx, Type::ObjectType(script->function()));
    4112                 :         else
    4113              16 :             pushed[0].addType(cx, Type::UnknownType());
    4114              87 :         break;
    4115                 : 
    4116                 :       default:
    4117                 :         /* Display fine-grained debug information first */
    4118               0 :         fprintf(stderr, "Unknown bytecode %02x at #%u:%05u\n", op, script->id(), offset);
    4119               0 :         TypeFailure(cx, "Unknown bytecode %02x", op);
    4120                 :     }
    4121                 : 
    4122         2004044 :     return true;
    4123                 : }
    4124                 : 
    4125                 : void
    4126           38782 : ScriptAnalysis::analyzeTypes(JSContext *cx)
    4127                 : {
    4128           38782 :     JS_ASSERT(!ranInference());
    4129                 : 
    4130           38782 :     if (OOM()) {
    4131               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4132               0 :         return;
    4133                 :     }
    4134                 : 
    4135                 :     /*
    4136                 :      * Refuse to analyze the types in a script which is compileAndGo but is
    4137                 :      * running against a global with a cleared scope. Per GlobalObject::clear,
    4138                 :      * we won't be running anymore compileAndGo code against the global
    4139                 :      * (moreover, after clearing our analysis results will be wrong for the
    4140                 :      * script and trying to reanalyze here can cause reentrance problems if we
    4141                 :      * try to reinitialize standard classes that were cleared).
    4142                 :      */
    4143           38782 :     if (script->hasClearedGlobal())
    4144               0 :         return;
    4145                 : 
    4146           38782 :     if (!ranSSA()) {
    4147           38782 :         analyzeSSA(cx);
    4148           38782 :         if (failed())
    4149               0 :             return;
    4150                 :     }
    4151                 : 
    4152                 :     /*
    4153                 :      * Set this early to avoid reentrance. Any failures are OOMs, and will nuke
    4154                 :      * all types in the compartment.
    4155                 :      */
    4156           38782 :     ranInference_ = true;
    4157                 : 
    4158                 :     /* Make sure the initial type set of all local vars includes void. */
    4159           71082 :     for (unsigned i = 0; i < script->nfixed; i++)
    4160           32300 :         TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
    4161                 : 
    4162           38782 :     TypeScriptNesting *nesting = script->function() ? script->nesting() : NULL;
    4163           38782 :     if (nesting && nesting->parent) {
    4164                 :         /*
    4165                 :          * Check whether NAME accesses can be resolved in parent scopes, and
    4166                 :          * detach from the parent if so. Even if outdated activations of this
    4167                 :          * function are live when the parent is called again, we do not need to
    4168                 :          * consider this reentrance as no state in the parent will be used.
    4169                 :          */
    4170            1182 :         if (!nesting->parent->ensureRanInference(cx))
    4171               0 :             return;
    4172                 : 
    4173            1182 :         bool detached = false;
    4174                 : 
    4175                 :         /* Don't track for leaf scripts which have no free variables. */
    4176            1182 :         if (!usesScopeChain() && !script->isOuterFunction) {
    4177              52 :             DetachNestingParent(script);
    4178              52 :             detached = true;
    4179                 :         }
    4180                 : 
    4181                 :         /*
    4182                 :          * If the names bound by the script are extensible (DEFFUN, EVAL, ...),
    4183                 :          * don't resolve NAME accesses into the parent.
    4184                 :          */
    4185            1182 :         if (!detached && extendsScope()) {
    4186              50 :             DetachNestingParent(script);
    4187              50 :             detached = true;
    4188                 :         }
    4189                 : 
    4190                 : 
    4191            1182 :         if (!detached) {
    4192                 :             /*
    4193                 :              * Don't track for parents which add call objects or are generators,
    4194                 :              * don't resolve NAME accesses into the parent.
    4195                 :              */
    4196            1080 :             if (nesting->parent->analysis()->addsScopeObjects() || 
    4197                 :                 JSOp(*nesting->parent->code) == JSOP_GENERATOR)
    4198                 :             {
    4199              84 :                 DetachNestingParent(script);
    4200                 :             }
    4201                 :         }
    4202                 :     }
    4203                 : 
    4204           77564 :     TypeInferenceState state(cx);
    4205                 : 
    4206           38782 :     unsigned offset = 0;
    4207         2107993 :     while (offset < script->length) {
    4208         2030429 :         Bytecode *code = maybeCode(offset);
    4209                 : 
    4210         2030429 :         jsbytecode *pc = script->code + offset;
    4211                 : 
    4212         2030429 :         if (code && !analyzeTypesBytecode(cx, offset, state)) {
    4213               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    4214                 :             return;
    4215                 :         }
    4216                 : 
    4217         2030429 :         offset += GetBytecodeLength(pc);
    4218                 :     }
    4219                 : 
    4220           53692 :     for (unsigned i = 0; i < state.phiNodes.length(); i++) {
    4221           14910 :         SSAPhiNode *node = state.phiNodes[i];
    4222           39654 :         for (unsigned j = 0; j < node->length; j++) {
    4223           24744 :             const SSAValue &v = node->options[j];
    4224           24744 :             getValueTypes(v)->addSubset(cx, &node->types);
    4225                 :         }
    4226                 :     }
    4227                 : 
    4228                 :     /*
    4229                 :      * Replay any dynamic type results which have been generated for the script
    4230                 :      * either because we ran the interpreter some before analyzing or because
    4231                 :      * we are reanalyzing after a GC.
    4232                 :      */
    4233           38782 :     TypeResult *result = script->types->dynamicList;
    4234           78422 :     while (result) {
    4235             858 :         if (result->offset != UINT32_MAX) {
    4236             762 :             pushedTypes(result->offset)->addType(cx, result->type);
    4237                 :         } else {
    4238                 :             /* Custom for-in loop iteration has happened in this script. */
    4239              96 :             state.forTypes->addType(cx, Type::UnknownType());
    4240                 :         }
    4241             858 :         result = result->next;
    4242                 :     }
    4243                 : 
    4244           38782 :     if (!script->usesArguments || script->createdArgs)
    4245                 :         return;
    4246                 : 
    4247                 :     /*
    4248                 :      * Do additional analysis to determine whether the arguments object in the
    4249                 :      * script can escape.
    4250                 :      */
    4251                 : 
    4252                 :     /*
    4253                 :      * Note: don't check for strict mode code here, even though arguments
    4254                 :      * accesses in such scripts will always be deoptimized. These scripts can
    4255                 :      * have a JSOP_ARGUMENTS in their prologue which the usesArguments check
    4256                 :      * above does not account for. We filter in the interpreter and JITs
    4257                 :      * themselves.
    4258                 :      */
    4259            1155 :     if (script->function()->isHeavyweight() || cx->compartment->debugMode() || localsAliasStack()) {
    4260             525 :         MarkArgumentsCreated(cx, script);
    4261                 :         return;
    4262                 :     }
    4263                 : 
    4264             630 :     offset = 0;
    4265            7589 :     while (offset < script->length) {
    4266            6632 :         Bytecode *code = maybeCode(offset);
    4267            6632 :         jsbytecode *pc = script->code + offset;
    4268                 : 
    4269            6632 :         if (code && JSOp(*pc) == JSOP_ARGUMENTS) {
    4270            1694 :             Vector<SSAValue> seen(cx);
    4271             847 :             if (!followEscapingArguments(cx, SSAValue::PushedValue(offset, 0), &seen)) {
    4272             303 :                 MarkArgumentsCreated(cx, script);
    4273                 :                 return;
    4274                 :             }
    4275                 :         }
    4276                 : 
    4277            6329 :         offset += GetBytecodeLength(pc);
    4278                 :     }
    4279                 : 
    4280                 :     /*
    4281                 :      * The VM is now free to use the arguments in this script lazily. If we end
    4282                 :      * up creating an arguments object for the script in the future or regard
    4283                 :      * the arguments as escaping, we need to walk the stack and replace lazy
    4284                 :      * arguments objects with actual arguments objects.
    4285                 :      */
    4286             327 :     script->usedLazyArgs = true;
    4287                 : }
    4288                 : 
    4289                 : bool
    4290            1163 : ScriptAnalysis::followEscapingArguments(JSContext *cx, const SSAValue &v, Vector<SSAValue> *seen)
    4291                 : {
    4292                 :     /*
    4293                 :      * trackUseChain is false for initial values of variables, which
    4294                 :      * cannot hold the script's arguments object.
    4295                 :      */
    4296            1163 :     if (!trackUseChain(v))
    4297               0 :         return true;
    4298                 : 
    4299            1992 :     for (unsigned i = 0; i < seen->length(); i++) {
    4300             871 :         if (v == (*seen)[i])
    4301              42 :             return true;
    4302                 :     }
    4303            1121 :     if (!seen->append(v)) {
    4304               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4305               0 :         return false;
    4306                 :     }
    4307                 : 
    4308            1121 :     SSAUseChain *use = useChain(v);
    4309            3098 :     while (use) {
    4310            1196 :         if (!followEscapingArguments(cx, use, seen))
    4311             340 :             return false;
    4312             856 :         use = use->next;
    4313                 :     }
    4314                 : 
    4315             781 :     return true;
    4316                 : }
    4317                 : 
    4318                 : bool
    4319            1196 : ScriptAnalysis::followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<SSAValue> *seen)
    4320                 : {
    4321            1196 :     if (!use->popped)
    4322              55 :         return followEscapingArguments(cx, SSAValue::PhiValue(use->offset, use->u.phi), seen);
    4323                 : 
    4324            1141 :     jsbytecode *pc = script->code + use->offset;
    4325            1141 :     uint32_t which = use->u.which;
    4326                 : 
    4327            1141 :     JSOp op = JSOp(*pc);
    4328                 : 
    4329            1141 :     if (op == JSOP_POP || op == JSOP_POPN)
    4330              66 :         return true;
    4331                 : 
    4332                 :     /* Allow GETELEM and LENGTH on arguments objects that don't escape. */
    4333                 : 
    4334                 :     /*
    4335                 :      * Note: if the element index is not an integer we will mark the arguments
    4336                 :      * as escaping at the access site.
    4337                 :      */
    4338            1075 :     if (op == JSOP_GETELEM && which == 1)
    4339             460 :         return true;
    4340                 : 
    4341             615 :     if (op == JSOP_LENGTH)
    4342             135 :         return true;
    4343                 : 
    4344                 :     /* Allow assignments to non-closed locals (but not arguments). */
    4345                 : 
    4346             480 :     if (op == JSOP_SETLOCAL) {
    4347             112 :         uint32_t slot = GetBytecodeSlot(script, pc);
    4348             112 :         if (!trackSlot(slot))
    4349              25 :             return false;
    4350              87 :         if (!followEscapingArguments(cx, SSAValue::PushedValue(use->offset, 0), seen))
    4351               3 :             return false;
    4352              84 :         return followEscapingArguments(cx, SSAValue::WrittenVar(slot, use->offset), seen);
    4353                 :     }
    4354                 : 
    4355             368 :     if (op == JSOP_GETLOCAL)
    4356              90 :         return followEscapingArguments(cx, SSAValue::PushedValue(use->offset, 0), seen);
    4357                 : 
    4358             278 :     return false;
    4359                 : }
    4360                 : 
    4361                 : bool
    4362           15042 : ScriptAnalysis::integerOperation(JSContext *cx, jsbytecode *pc)
    4363                 : {
    4364           15042 :     JS_ASSERT(uint32_t(pc - script->code) < script->length);
    4365                 : 
    4366           15042 :     switch (JSOp(*pc)) {
    4367                 : 
    4368                 :       case JSOP_INCARG:
    4369                 :       case JSOP_DECARG:
    4370                 :       case JSOP_ARGINC:
    4371                 :       case JSOP_ARGDEC:
    4372                 :       case JSOP_INCLOCAL:
    4373                 :       case JSOP_DECLOCAL:
    4374                 :       case JSOP_LOCALINC:
    4375                 :       case JSOP_LOCALDEC: {
    4376           11946 :         if (pushedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
    4377              73 :             return false;
    4378           11873 :         uint32_t slot = GetBytecodeSlot(script, pc);
    4379           11873 :         if (trackSlot(slot)) {
    4380           11873 :             if (poppedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
    4381              22 :                 return false;
    4382                 :         }
    4383           11851 :         return true;
    4384                 :       }
    4385                 : 
    4386                 :       case JSOP_ADD:
    4387                 :       case JSOP_SUB:
    4388                 :       case JSOP_MUL:
    4389                 :       case JSOP_DIV:
    4390            3073 :         if (pushedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
    4391            1227 :             return false;
    4392            1846 :         if (poppedTypes(pc, 0)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
    4393              63 :             return false;
    4394            1783 :         if (poppedTypes(pc, 1)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
    4395             152 :             return false;
    4396            1631 :         return true;
    4397                 : 
    4398                 :       default:
    4399              23 :         return true;
    4400                 :     }
    4401                 : }
    4402                 : 
    4403                 : /*
    4404                 :  * Persistent constraint clearing out newScript and definite properties from
    4405                 :  * an object should a property on another object get a setter.
    4406                 :  */
    4407                 : class TypeConstraintClearDefiniteSetter : public TypeConstraint
    4408                 : {
    4409                 : public:
    4410                 :     TypeObject *object;
    4411                 : 
    4412            2213 :     TypeConstraintClearDefiniteSetter(TypeObject *object)
    4413            2213 :         : TypeConstraint("clearDefiniteSetter"), object(object)
    4414            2213 :     {}
    4415                 : 
    4416              45 :     void newPropertyState(JSContext *cx, TypeSet *source)
    4417                 :     {
    4418              45 :         if (!object->newScript)
    4419               0 :             return;
    4420                 :         /*
    4421                 :          * Clear out the newScript shape and definite property information from
    4422                 :          * an object if the source type set could be a setter or could be
    4423                 :          * non-writable, both of which are indicated by the source type set
    4424                 :          * being marked as configured.
    4425                 :          */
    4426              45 :         if (!(object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED) && source->isOwnProperty(true))
    4427              25 :             object->clearNewScript(cx);
    4428                 :     }
    4429                 : 
    4430              65 :     void newType(JSContext *cx, TypeSet *source, Type type) {}
    4431                 : };
    4432                 : 
    4433                 : /*
    4434                 :  * Constraint which clears definite properties on an object should a type set
    4435                 :  * contain any types other than a single object.
    4436                 :  */
    4437                 : class TypeConstraintClearDefiniteSingle : public TypeConstraint
    4438                 : {
    4439                 : public:
    4440                 :     TypeObject *object;
    4441                 : 
    4442              78 :     TypeConstraintClearDefiniteSingle(TypeObject *object)
    4443              78 :         : TypeConstraint("clearDefiniteSingle"), object(object)
    4444              78 :     {}
    4445                 : 
    4446              83 :     void newType(JSContext *cx, TypeSet *source, Type type) {
    4447              83 :         if (object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED)
    4448               0 :             return;
    4449                 : 
    4450              83 :         if (source->baseFlags() || source->getObjectCount() > 1)
    4451               5 :             object->clearNewScript(cx);
    4452                 :     }
    4453                 : };
    4454                 : 
    4455                 : static bool
    4456            1446 : AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSObject **pbaseobj,
    4457                 :                            Vector<TypeNewScript::Initializer> *initializerList)
    4458                 : {
    4459                 :     /*
    4460                 :      * When invoking 'new' on the specified script, try to find some properties
    4461                 :      * which will definitely be added to the created object before it has a
    4462                 :      * chance to escape and be accessed elsewhere.
    4463                 :      *
    4464                 :      * Returns true if the entire script was analyzed (pbaseobj has been
    4465                 :      * preserved), false if we had to bail out part way through (pbaseobj may
    4466                 :      * have been cleared).
    4467                 :      */
    4468                 : 
    4469            1446 :     if (initializerList->length() > 50) {
    4470                 :         /*
    4471                 :          * Bail out on really long initializer lists (far longer than maximum
    4472                 :          * number of properties we can track), we may be recursing.
    4473                 :          */
    4474               0 :         return false;
    4475                 :     }
    4476                 : 
    4477            1446 :     JSScript *script = fun->script();
    4478            1446 :     JS_ASSERT(!script->isInnerFunction);
    4479                 : 
    4480            1446 :     if (!script->ensureRanAnalysis(cx, fun) || !script->ensureRanInference(cx)) {
    4481               0 :         *pbaseobj = NULL;
    4482               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4483               0 :         return false;
    4484                 :     }
    4485                 : 
    4486            1446 :     if (script->hasClearedGlobal())
    4487               0 :         return false;
    4488                 : 
    4489            1446 :     ScriptAnalysis *analysis = script->analysis();
    4490                 : 
    4491                 :     /*
    4492                 :      * Offset of the last bytecode which popped 'this' and which we have
    4493                 :      * processed. For simplicity, we scan for places where 'this' is pushed
    4494                 :      * and immediately analyze the place where that pushed value is popped.
    4495                 :      * This runs the risk of doing things out of order, if the script looks
    4496                 :      * something like 'this.f  = (this.g = ...)', so we watch and bail out if
    4497                 :      * a 'this' is pushed before the previous 'this' value was popped.
    4498                 :      */
    4499            1446 :     uint32_t lastThisPopped = 0;
    4500                 : 
    4501            1446 :     unsigned nextOffset = 0;
    4502           12714 :     while (nextOffset < script->length) {
    4503           11238 :         unsigned offset = nextOffset;
    4504           11238 :         jsbytecode *pc = script->code + offset;
    4505                 : 
    4506           11238 :         JSOp op = JSOp(*pc);
    4507                 : 
    4508           11238 :         nextOffset += GetBytecodeLength(pc);
    4509                 : 
    4510           11238 :         Bytecode *code = analysis->maybeCode(pc);
    4511           11238 :         if (!code)
    4512              40 :             continue;
    4513                 : 
    4514                 :         /*
    4515                 :          * End analysis after the first return statement from the script,
    4516                 :          * returning success if the return is unconditional.
    4517                 :          */
    4518           11198 :         if (op == JSOP_RETURN || op == JSOP_STOP || op == JSOP_RETRVAL) {
    4519            1072 :             if (offset < lastThisPopped) {
    4520               0 :                 *pbaseobj = NULL;
    4521               0 :                 return false;
    4522                 :             }
    4523            1072 :             return code->unconditional;
    4524                 :         }
    4525                 : 
    4526                 :         /* 'this' can escape through a call to eval. */
    4527           10126 :         if (op == JSOP_EVAL) {
    4528              75 :             if (offset < lastThisPopped)
    4529               0 :                 *pbaseobj = NULL;
    4530              75 :             return false;
    4531                 :         }
    4532                 : 
    4533                 :         /*
    4534                 :          * We are only interested in places where 'this' is popped. The new
    4535                 :          * 'this' value cannot escape and be accessed except through such uses.
    4536                 :          */
    4537           10051 :         if (op != JSOP_THIS)
    4538            8726 :             continue;
    4539                 : 
    4540                 :         /* Maintain ordering property on how 'this' is used, as described above. */
    4541            1325 :         if (offset < lastThisPopped) {
    4542              10 :             *pbaseobj = NULL;
    4543              10 :             return false;
    4544                 :         }
    4545                 : 
    4546            1315 :         SSAValue thisv = SSAValue::PushedValue(offset, 0);
    4547            1315 :         SSAUseChain *uses = analysis->useChain(thisv);
    4548                 : 
    4549            1315 :         JS_ASSERT(uses);
    4550            1315 :         if (uses->next || !uses->popped) {
    4551                 :             /* 'this' value popped in more than one place. */
    4552              24 :             return false;
    4553                 :         }
    4554                 : 
    4555            1291 :         lastThisPopped = uses->offset;
    4556                 : 
    4557                 :         /* Only handle 'this' values popped in unconditional code. */
    4558            1291 :         Bytecode *poppedCode = analysis->maybeCode(uses->offset);
    4559            1291 :         if (!poppedCode || !poppedCode->unconditional)
    4560              25 :             return false;
    4561                 : 
    4562            1266 :         pc = script->code + uses->offset;
    4563            1266 :         op = JSOp(*pc);
    4564                 : 
    4565            1266 :         JSObject *obj = *pbaseobj;
    4566                 : 
    4567            1266 :         if (op == JSOP_SETPROP && uses->u.which == 1) {
    4568                 :             /*
    4569                 :              * Don't use GetAtomId here, we need to watch for SETPROP on
    4570                 :              * integer properties and bail out. We can't mark the aggregate
    4571                 :              * JSID_VOID type property as being in a definite slot.
    4572                 :              */
    4573            1057 :             jsid id = ATOM_TO_JSID(script->getAtom(GET_UINT32_INDEX(pc)));
    4574            1057 :             if (MakeTypeId(cx, id) != id)
    4575               5 :                 return false;
    4576            1052 :             if (id == id_prototype(cx) || id == id___proto__(cx) || id == id_constructor(cx))
    4577               0 :                 return false;
    4578                 : 
    4579                 :             /*
    4580                 :              * Ensure that if the properties named here could have a setter or
    4581                 :              * a permanent property in any transitive prototype, the definite
    4582                 :              * properties get cleared from the shape.
    4583                 :              */
    4584            1052 :             JSObject *parent = type->proto;
    4585            4317 :             while (parent) {
    4586            2228 :                 TypeObject *parentObject = parent->getType(cx);
    4587            2228 :                 if (parentObject->unknownProperties())
    4588               0 :                     return false;
    4589            2228 :                 TypeSet *parentTypes = parentObject->getProperty(cx, id, false);
    4590            2228 :                 if (!parentTypes || parentTypes->isOwnProperty(true))
    4591              15 :                     return false;
    4592            2213 :                 parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSetter>(type));
    4593            2213 :                 parent = parent->getProto();
    4594                 :             }
    4595                 : 
    4596            1037 :             unsigned slotSpan = obj->slotSpan();
    4597            1037 :             if (!DefineNativeProperty(cx, obj, id, UndefinedValue(), NULL, NULL,
    4598            1037 :                                       JSPROP_ENUMERATE, 0, 0, DNP_SKIP_TYPE)) {
    4599               0 :                 cx->compartment->types.setPendingNukeTypes(cx);
    4600               0 :                 *pbaseobj = NULL;
    4601               0 :                 return false;
    4602                 :             }
    4603                 : 
    4604            1037 :             if (obj->inDictionaryMode()) {
    4605               0 :                 *pbaseobj = NULL;
    4606               0 :                 return false;
    4607                 :             }
    4608                 : 
    4609            1037 :             if (obj->slotSpan() == slotSpan) {
    4610                 :                 /* Set a duplicate property. */
    4611               8 :                 return false;
    4612                 :             }
    4613                 : 
    4614            1029 :             TypeNewScript::Initializer setprop(TypeNewScript::Initializer::SETPROP, uses->offset);
    4615            1029 :             if (!initializerList->append(setprop)) {
    4616               0 :                 cx->compartment->types.setPendingNukeTypes(cx);
    4617               0 :                 *pbaseobj = NULL;
    4618               0 :                 return false;
    4619                 :             }
    4620                 : 
    4621            1029 :             if (obj->slotSpan() >= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT)) {
    4622                 :                 /* Maximum number of definite properties added. */
    4623               0 :                 return false;
    4624            1029 :             }
    4625             209 :         } else if (op == JSOP_FUNCALL && uses->u.which == GET_ARGC(pc) - 1) {
    4626                 :             /*
    4627                 :              * Passed as the first parameter to Function.call. Follow control
    4628                 :              * into the callee, and add any definite properties it assigns to
    4629                 :              * the object as well. :TODO: This is narrow pattern matching on
    4630                 :              * the inheritance patterns seen in the v8-deltablue benchmark, and
    4631                 :              * needs robustness against other ways initialization can cross
    4632                 :              * script boundaries.
    4633                 :              *
    4634                 :              * Add constraints ensuring we are calling Function.call on a
    4635                 :              * particular script, removing definite properties from the result
    4636                 :              */
    4637                 : 
    4638                 :             /* Callee/this must have been pushed by a CALLPROP. */
    4639              47 :             SSAValue calleev = analysis->poppedValue(pc, GET_ARGC(pc) + 1);
    4640              47 :             if (calleev.kind() != SSAValue::PUSHED)
    4641               0 :                 return false;
    4642              47 :             jsbytecode *calleepc = script->code + calleev.pushedOffset();
    4643              47 :             if (JSOp(*calleepc) != JSOP_CALLPROP)
    4644               0 :                 return false;
    4645                 : 
    4646                 :             /*
    4647                 :              * This code may not have run yet, break any type barriers involved
    4648                 :              * in performing the call (for the greater good!).
    4649                 :              */
    4650              47 :             analysis->breakTypeBarriersSSA(cx, analysis->poppedValue(calleepc, 0));
    4651              47 :             analysis->breakTypeBarriers(cx, calleepc - script->code, true);
    4652                 : 
    4653              47 :             TypeSet *funcallTypes = analysis->poppedTypes(pc, GET_ARGC(pc) + 1);
    4654              47 :             TypeSet *scriptTypes = analysis->poppedTypes(pc, GET_ARGC(pc));
    4655                 : 
    4656                 :             /* Need to definitely be calling Function.call on a specific script. */
    4657              47 :             JSObject *funcallObj = funcallTypes->getSingleton(cx, false);
    4658              47 :             JSObject *scriptObj = scriptTypes->getSingleton(cx, false);
    4659              86 :             if (!funcallObj || !scriptObj || !scriptObj->isFunction() ||
    4660              39 :                 !scriptObj->toFunction()->isInterpreted()) {
    4661               8 :                 return false;
    4662                 :             }
    4663                 : 
    4664              39 :             JSFunction *function = scriptObj->toFunction();
    4665              39 :             JS_ASSERT(!function->script()->isInnerFunction);
    4666                 : 
    4667                 :             /*
    4668                 :              * Generate constraints to clear definite properties from the type
    4669                 :              * should the Function.call or callee itself change in the future.
    4670                 :              */
    4671                 :             funcallTypes->add(cx,
    4672              39 :                 cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
    4673                 :             scriptTypes->add(cx,
    4674              39 :                 cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
    4675                 : 
    4676              39 :             TypeNewScript::Initializer pushframe(TypeNewScript::Initializer::FRAME_PUSH, uses->offset);
    4677              39 :             if (!initializerList->append(pushframe)) {
    4678               0 :                 cx->compartment->types.setPendingNukeTypes(cx);
    4679               0 :                 *pbaseobj = NULL;
    4680               0 :                 return false;
    4681                 :             }
    4682                 : 
    4683              39 :             if (!AnalyzeNewScriptProperties(cx, type, function,
    4684              39 :                                             pbaseobj, initializerList)) {
    4685              12 :                 return false;
    4686                 :             }
    4687                 : 
    4688              27 :             TypeNewScript::Initializer popframe(TypeNewScript::Initializer::FRAME_POP, 0);
    4689              27 :             if (!initializerList->append(popframe)) {
    4690               0 :                 cx->compartment->types.setPendingNukeTypes(cx);
    4691               0 :                 *pbaseobj = NULL;
    4692               0 :                 return false;
    4693              27 :             }
    4694                 : 
    4695                 :             /*
    4696                 :              * The callee never lets the 'this' value escape, continue looking
    4697                 :              * for definite properties in the remainder of this script.
    4698                 :              */
    4699                 :         } else {
    4700                 :             /* Unhandled use of 'this'. */
    4701             162 :             return false;
    4702                 :         }
    4703                 :     }
    4704                 : 
    4705                 :     /* Will have hit a STOP or similar, unless the script always throws. */
    4706              30 :     return true;
    4707                 : }
    4708                 : 
    4709                 : /*
    4710                 :  * Either make the newScript information for type when it is constructed
    4711                 :  * by the specified script, or regenerate the constraints for an existing
    4712                 :  * newScript on the type after they were cleared by a GC.
    4713                 :  */
    4714                 : static void
    4715            1467 : CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
    4716                 : {
    4717            1467 :     if (type->unknownProperties() || fun->script()->isInnerFunction)
    4718              60 :         return;
    4719                 : 
    4720                 :     /* Strawman object to add properties to and watch for duplicates. */
    4721            1407 :     JSObject *baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
    4722            1407 :     if (!baseobj) {
    4723               0 :         if (type->newScript)
    4724               0 :             type->clearNewScript(cx);
    4725               0 :         return;
    4726                 :     }
    4727                 : 
    4728            2814 :     Vector<TypeNewScript::Initializer> initializerList(cx);
    4729            1407 :     AnalyzeNewScriptProperties(cx, type, fun, &baseobj, &initializerList);
    4730            1407 :     if (!baseobj || baseobj->slotSpan() == 0 || !!(type->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED)) {
    4731             825 :         if (type->newScript)
    4732               0 :             type->clearNewScript(cx);
    4733                 :         return;
    4734                 :     }
    4735                 : 
    4736                 :     /*
    4737                 :      * If the type already has a new script, we are just regenerating the type
    4738                 :      * constraints and don't need to make another TypeNewScript. Make sure that
    4739                 :      * the properties added to baseobj match the type's definite properties.
    4740                 :      */
    4741             582 :     if (type->newScript) {
    4742               2 :         if (!type->matchDefiniteProperties(baseobj))
    4743               0 :             type->clearNewScript(cx);
    4744                 :         return;
    4745                 :     }
    4746                 : 
    4747             580 :     gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
    4748                 : 
    4749                 :     /* We should not have overflowed the maximum number of fixed slots for an object. */
    4750             580 :     JS_ASSERT(gc::GetGCKindSlots(kind) >= baseobj->slotSpan());
    4751                 : 
    4752             580 :     TypeNewScript::Initializer done(TypeNewScript::Initializer::DONE, 0);
    4753                 : 
    4754                 :     /*
    4755                 :      * The base object may have been created with a different finalize kind
    4756                 :      * than we will use for subsequent new objects. Generate an object with the
    4757                 :      * appropriate final shape.
    4758                 :      */
    4759                 :     baseobj = NewReshapedObject(cx, type, baseobj->getParent(), kind,
    4760             580 :                                 baseobj->lastProperty());
    4761            1740 :     if (!baseobj ||
    4762             580 :         !type->addDefiniteProperties(cx, baseobj) ||
    4763             580 :         !initializerList.append(done)) {
    4764               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4765                 :         return;
    4766                 :     }
    4767                 : 
    4768                 :     size_t numBytes = sizeof(TypeNewScript)
    4769             580 :                     + (initializerList.length() * sizeof(TypeNewScript::Initializer));
    4770             580 :     type->newScript = (TypeNewScript *) cx->calloc_(numBytes);
    4771             580 :     if (!type->newScript) {
    4772               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4773                 :         return;
    4774                 :     }
    4775                 : 
    4776             580 :     type->newScript->fun = fun;
    4777             580 :     type->newScript->allocKind = kind;
    4778             580 :     type->newScript->shape = baseobj->lastProperty();
    4779                 : 
    4780             580 :     type->newScript->initializerList = (TypeNewScript::Initializer *)
    4781             580 :         ((char *) type->newScript.get() + sizeof(TypeNewScript));
    4782             580 :     PodCopy(type->newScript->initializerList, initializerList.begin(), initializerList.length());
    4783                 : }
    4784                 : 
    4785                 : /////////////////////////////////////////////////////////////////////
    4786                 : // Printing
    4787                 : /////////////////////////////////////////////////////////////////////
    4788                 : 
    4789                 : void
    4790               0 : ScriptAnalysis::printTypes(JSContext *cx)
    4791                 : {
    4792               0 :     AutoEnterAnalysis enter(script->compartment());
    4793               0 :     TypeCompartment *compartment = &script->compartment()->types;
    4794                 : 
    4795                 :     /*
    4796                 :      * Check if there are warnings for used values with unknown types, and build
    4797                 :      * statistics about the size of type sets found for stack values.
    4798                 :      */
    4799               0 :     for (unsigned offset = 0; offset < script->length; offset++) {
    4800               0 :         if (!maybeCode(offset))
    4801               0 :             continue;
    4802                 : 
    4803               0 :         jsbytecode *pc = script->code + offset;
    4804                 : 
    4805               0 :         if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
    4806               0 :             continue;
    4807                 : 
    4808               0 :         unsigned defCount = GetDefCount(script, offset);
    4809               0 :         if (!defCount)
    4810               0 :             continue;
    4811                 : 
    4812               0 :         for (unsigned i = 0; i < defCount; i++) {
    4813               0 :             TypeSet *types = pushedTypes(offset, i);
    4814                 : 
    4815               0 :             if (types->unknown()) {
    4816               0 :                 compartment->typeCountOver++;
    4817               0 :                 continue;
    4818                 :             }
    4819                 : 
    4820               0 :             unsigned typeCount = 0;
    4821                 : 
    4822               0 :             if (types->hasAnyFlag(TYPE_FLAG_ANYOBJECT) || types->getObjectCount() != 0)
    4823               0 :                 typeCount++;
    4824               0 :             for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
    4825               0 :                 if (types->hasAnyFlag(flag))
    4826               0 :                     typeCount++;
    4827                 :             }
    4828                 : 
    4829                 :             /*
    4830                 :              * Adjust the type counts for floats: values marked as floats
    4831                 :              * are also marked as ints by the inference, but for counting
    4832                 :              * we don't consider these to be separate types.
    4833                 :              */
    4834               0 :             if (types->hasAnyFlag(TYPE_FLAG_DOUBLE)) {
    4835               0 :                 JS_ASSERT(types->hasAnyFlag(TYPE_FLAG_INT32));
    4836               0 :                 typeCount--;
    4837                 :             }
    4838                 : 
    4839               0 :             if (typeCount > TypeCompartment::TYPE_COUNT_LIMIT) {
    4840               0 :                 compartment->typeCountOver++;
    4841               0 :             } else if (typeCount == 0) {
    4842                 :                 /* Ignore values without types, this may be unreached code. */
    4843                 :             } else {
    4844               0 :                 compartment->typeCounts[typeCount-1]++;
    4845                 :             }
    4846                 :         }
    4847                 :     }
    4848                 : 
    4849                 : #ifdef DEBUG
    4850                 : 
    4851               0 :     if (script->function())
    4852               0 :         printf("Function");
    4853               0 :     else if (script->isCachedEval)
    4854               0 :         printf("Eval");
    4855                 :     else
    4856               0 :         printf("Main");
    4857               0 :     printf(" #%u %s (line %d):\n", script->id(), script->filename, script->lineno);
    4858                 : 
    4859               0 :     printf("locals:");
    4860               0 :     printf("\n    return:");
    4861               0 :     TypeScript::ReturnTypes(script)->print(cx);
    4862               0 :     printf("\n    this:");
    4863               0 :     TypeScript::ThisTypes(script)->print(cx);
    4864                 : 
    4865               0 :     for (unsigned i = 0; script->function() && i < script->function()->nargs; i++) {
    4866               0 :         printf("\n    arg%u:", i);
    4867               0 :         TypeScript::ArgTypes(script, i)->print(cx);
    4868                 :     }
    4869               0 :     for (unsigned i = 0; i < script->nfixed; i++) {
    4870               0 :         if (!trackSlot(LocalSlot(script, i))) {
    4871               0 :             printf("\n    local%u:", i);
    4872               0 :             TypeScript::LocalTypes(script, i)->print(cx);
    4873                 :         }
    4874                 :     }
    4875               0 :     printf("\n");
    4876                 : 
    4877               0 :     for (unsigned offset = 0; offset < script->length; offset++) {
    4878               0 :         if (!maybeCode(offset))
    4879               0 :             continue;
    4880                 : 
    4881               0 :         jsbytecode *pc = script->code + offset;
    4882                 : 
    4883               0 :         PrintBytecode(cx, script, pc);
    4884                 : 
    4885               0 :         if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
    4886               0 :             continue;
    4887                 : 
    4888               0 :         if (js_CodeSpec[*pc].format & JOF_TYPESET) {
    4889               0 :             TypeSet *types = script->analysis()->bytecodeTypes(pc);
    4890               0 :             printf("  typeset %d:", (int) (types - script->types->typeArray()));
    4891               0 :             types->print(cx);
    4892               0 :             printf("\n");
    4893                 :         }
    4894                 : 
    4895               0 :         unsigned defCount = GetDefCount(script, offset);
    4896               0 :         for (unsigned i = 0; i < defCount; i++) {
    4897               0 :             printf("  type %d:", i);
    4898               0 :             pushedTypes(offset, i)->print(cx);
    4899               0 :             printf("\n");
    4900                 :         }
    4901                 : 
    4902               0 :         if (getCode(offset).monitoredTypes)
    4903               0 :             printf("  monitored\n");
    4904                 : 
    4905               0 :         TypeBarrier *barrier = getCode(offset).typeBarriers;
    4906               0 :         if (barrier != NULL) {
    4907               0 :             printf("  barrier:");
    4908               0 :             while (barrier) {
    4909               0 :                 printf(" %s", TypeString(barrier->type));
    4910               0 :                 barrier = barrier->next;
    4911                 :             }
    4912               0 :             printf("\n");
    4913                 :         }
    4914                 :     }
    4915                 : 
    4916               0 :     printf("\n");
    4917                 : 
    4918                 : #endif /* DEBUG */
    4919                 : 
    4920               0 : }
    4921                 : 
    4922                 : /////////////////////////////////////////////////////////////////////
    4923                 : // Interface functions
    4924                 : /////////////////////////////////////////////////////////////////////
    4925                 : 
    4926                 : namespace js {
    4927                 : namespace types {
    4928                 : 
    4929                 : void
    4930            2377 : MarkIteratorUnknownSlow(JSContext *cx)
    4931                 : {
    4932                 :     /* Check whether we are actually at an ITER opcode. */
    4933                 : 
    4934                 :     jsbytecode *pc;
    4935            2377 :     JSScript *script = cx->stack.currentScript(&pc);
    4936            2377 :     if (!script || !pc)
    4937               5 :         return;
    4938                 : 
    4939            2372 :     if (JSOp(*pc) != JSOP_ITER)
    4940             150 :         return;
    4941                 : 
    4942            4444 :     AutoEnterTypeInference enter(cx);
    4943                 : 
    4944                 :     /*
    4945                 :      * This script is iterating over an actual Iterator or Generator object, or
    4946                 :      * an object with a custom __iterator__ hook. In such cases 'for in' loops
    4947                 :      * can produce values other than strings, and the types of the ITER opcodes
    4948                 :      * in the script need to be updated. During analysis this is done with the
    4949                 :      * forTypes in the analysis state, but we don't keep a pointer to this type
    4950                 :      * set and need to scan the script to fix affected opcodes.
    4951                 :      */
    4952                 : 
    4953            2222 :     TypeResult *result = script->types->dynamicList;
    4954            4444 :     while (result) {
    4955            1772 :         if (result->offset == UINT32_MAX) {
    4956                 :             /* Already know about custom iterators used in this script. */
    4957            1772 :             JS_ASSERT(result->type.isUnknown());
    4958                 :             return;
    4959                 :         }
    4960               0 :         result = result->next;
    4961                 :     }
    4962                 : 
    4963             450 :     InferSpew(ISpewOps, "externalType: customIterator #%u", script->id());
    4964                 : 
    4965             450 :     result = cx->new_<TypeResult>(UINT32_MAX, Type::UnknownType());
    4966             450 :     if (!result) {
    4967               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    4968                 :         return;
    4969                 :     }
    4970             450 :     result->next = script->types->dynamicList;
    4971             450 :     script->types->dynamicList = result;
    4972                 : 
    4973             450 :     if (!script->hasAnalysis() || !script->analysis()->ranInference())
    4974                 :         return;
    4975                 : 
    4976             189 :     ScriptAnalysis *analysis = script->analysis();
    4977                 : 
    4978           25553 :     for (unsigned i = 0; i < script->length; i++) {
    4979           25364 :         jsbytecode *pc = script->code + i;
    4980           25364 :         if (!analysis->maybeCode(pc))
    4981           16159 :             continue;
    4982            9205 :         if (JSOp(*pc) == JSOP_ITERNEXT)
    4983             245 :             analysis->pushedTypes(pc, 0)->addType(cx, Type::UnknownType());
    4984                 :     }
    4985                 : 
    4986                 :     /* Trigger recompilation of any inline callers. */
    4987             189 :     if (script->function() && !script->function()->hasLazyType())
    4988              43 :         ObjectStateChange(cx, script->function()->type(), false, true);
    4989                 : }
    4990                 : 
    4991                 : void
    4992        12954220 : TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
    4993                 :                     const CallArgs &args, bool constructing)
    4994                 : {
    4995        12954220 :     unsigned nargs = callee->toFunction()->nargs;
    4996        12954220 :     JSScript *script = callee->toFunction()->script();
    4997                 : 
    4998        12954220 :     if (!constructing)
    4999        11641431 :         TypeScript::SetThis(cx, script, args.thisv());
    5000                 : 
    5001                 :     /*
    5002                 :      * Add constraints going up to the minimum of the actual and formal count.
    5003                 :      * If there are more actuals than formals the later values can only be
    5004                 :      * accessed through the arguments object, which is monitored.
    5005                 :      */
    5006        12954220 :     unsigned arg = 0;
    5007        33517190 :     for (; arg < args.length() && arg < nargs; arg++)
    5008        20562970 :         TypeScript::SetArgument(cx, script, arg, args[arg]);
    5009                 : 
    5010                 :     /* Watch for fewer actuals than formals to the call. */
    5011        13072015 :     for (; arg < nargs; arg++)
    5012          117795 :         TypeScript::SetArgument(cx, script, arg, UndefinedValue());
    5013        12954220 : }
    5014                 : 
    5015                 : static inline bool
    5016          665532 : IsAboutToBeFinalized(TypeObjectKey *key)
    5017                 : {
    5018                 :     /* Mask out the low bit indicating whether this is a type or JS object. */
    5019          665532 :     return !reinterpret_cast<const gc::Cell *>(uintptr_t(key) & ~1)->isMarked();
    5020                 : }
    5021                 : 
    5022                 : void
    5023          815404 : TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
    5024                 : {
    5025          815404 :     JS_ASSERT(cx->typeInferenceEnabled());
    5026         1630808 :     AutoEnterTypeInference enter(cx);
    5027                 : 
    5028                 :     /* Directly update associated type sets for applicable bytecodes. */
    5029          815404 :     if (js_CodeSpec[*pc].format & JOF_TYPESET) {
    5030             458 :         if (!script->ensureRanAnalysis(cx, NULL)) {
    5031               0 :             cx->compartment->types.setPendingNukeTypes(cx);
    5032                 :             return;
    5033                 :         }
    5034             458 :         TypeSet *types = script->analysis()->bytecodeTypes(pc);
    5035             458 :         if (!types->hasType(type)) {
    5036                 :             InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
    5037              73 :                       script->id(), pc - script->code, TypeString(type));
    5038              73 :             types->addType(cx, type);
    5039                 :         }
    5040                 :         return;
    5041                 :     }
    5042                 : 
    5043                 :     /*
    5044                 :      * For inc/dec ops, we need to go back and reanalyze the affected opcode
    5045                 :      * taking the overflow into account. We won't see an explicit adjustment
    5046                 :      * of the type of the thing being inc/dec'ed, nor will adding TYPE_DOUBLE to
    5047                 :      * the pushed value affect that type.
    5048                 :      */
    5049          814946 :     JSOp op = JSOp(*pc);
    5050          814946 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    5051          814946 :     if (cs->format & (JOF_INC | JOF_DEC)) {
    5052            1247 :         switch (op) {
    5053                 :           case JSOP_INCLOCAL:
    5054                 :           case JSOP_DECLOCAL:
    5055                 :           case JSOP_LOCALINC:
    5056                 :           case JSOP_LOCALDEC:
    5057                 :           case JSOP_INCARG:
    5058                 :           case JSOP_DECARG:
    5059                 :           case JSOP_ARGINC:
    5060                 :           case JSOP_ARGDEC: {
    5061                 :             /*
    5062                 :              * Just mark the slot's type as holding the new type. This captures
    5063                 :              * the effect if the slot is not being tracked, and if the slot
    5064                 :              * doesn't escape we will update the pushed types below to capture
    5065                 :              * the slot's value after this write.
    5066                 :              */
    5067            1247 :             uint32_t slot = GetBytecodeSlot(script, pc);
    5068            1247 :             if (slot < TotalSlots(script)) {
    5069            1229 :                 TypeSet *types = TypeScript::SlotTypes(script, slot);
    5070            1229 :                 types->addType(cx, type);
    5071                 :             }
    5072            1247 :             break;
    5073                 :           }
    5074                 : 
    5075                 :           default:;
    5076                 :         }
    5077                 :     }
    5078                 : 
    5079          814946 :     if (script->hasAnalysis() && script->analysis()->ranInference()) {
    5080                 :         /*
    5081                 :          * If the pushed set already has this type, we don't need to ensure
    5082                 :          * there is a TypeIntermediate. Either there already is one, or the
    5083                 :          * type could be determined from the script's other input type sets.
    5084                 :          */
    5085          252162 :         TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
    5086          252162 :         if (pushed->hasType(type))
    5087                 :             return;
    5088                 :     } else {
    5089                 :         /* Scan all intermediate types on the script to check for a dupe. */
    5090          562784 :         TypeResult *result, **pstart = &script->types->dynamicList, **presult = pstart;
    5091         2179080 :         while (*presult) {
    5092         1614803 :             result = *presult;
    5093         1614803 :             if (result->offset == unsigned(pc - script->code) && result->type == type) {
    5094          561291 :                 if (presult != pstart) {
    5095                 :                     /* Move to the head of the list, maintain LRU order. */
    5096          319341 :                     *presult = result->next;
    5097          319341 :                     result->next = *pstart;
    5098          319341 :                     *pstart = result;
    5099                 :                 }
    5100                 :                 return;
    5101                 :             }
    5102         1053512 :             presult = &result->next;
    5103                 :         }
    5104                 :     }
    5105                 : 
    5106                 :     InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
    5107            2348 :               script->id(), pc - script->code, TypeString(type));
    5108                 : 
    5109            2348 :     TypeResult *result = cx->new_<TypeResult>(pc - script->code, type);
    5110            2348 :     if (!result) {
    5111               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    5112                 :         return;
    5113                 :     }
    5114            2348 :     result->next = script->types->dynamicList;
    5115            2348 :     script->types->dynamicList = result;
    5116                 : 
    5117            2348 :     if (script->hasAnalysis() && script->analysis()->ranInference()) {
    5118             855 :         TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
    5119             855 :         pushed->addType(cx, type);
    5120                 :     }
    5121                 : 
    5122                 :     /* Trigger recompilation of any inline callers. */
    5123            2348 :     if (script->function() && !script->function()->hasLazyType())
    5124             487 :         ObjectStateChange(cx, script->function()->type(), false, true);
    5125                 : }
    5126                 : 
    5127                 : void
    5128        76761967 : TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
    5129                 : {
    5130                 :     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
    5131        76761967 :     if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
    5132               0 :         return;
    5133                 : 
    5134       153523934 :     AutoEnterTypeInference enter(cx);
    5135                 : 
    5136        76761967 :     if (!script->ensureRanAnalysis(cx, NULL)) {
    5137               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    5138                 :         return;
    5139                 :     }
    5140                 : 
    5141        76761967 :     Type type = GetValueType(cx, rval);
    5142        76761967 :     TypeSet *types = script->analysis()->bytecodeTypes(pc);
    5143        76761967 :     if (types->hasType(type))
    5144                 :         return;
    5145                 : 
    5146                 :     InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s",
    5147          361375 :               script->id(), pc - script->code, TypeString(type));
    5148          361375 :     types->addType(cx, type);
    5149                 : }
    5150                 : 
    5151                 : bool
    5152          470859 : TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
    5153                 : {
    5154          470859 :     JS_ASSERT(script->types && !script->types->hasScope());
    5155                 : 
    5156          941718 :     Root<JSScript*> scriptRoot(cx, &script);
    5157          941718 :     RootObject scopeRoot(cx, &scope);
    5158                 : 
    5159          470859 :     JSFunction *fun = script->function();
    5160          470859 :     bool nullClosure = fun && fun->isNullClosure();
    5161                 : 
    5162          470859 :     JS_ASSERT_IF(!fun, !script->isOuterFunction && !script->isInnerFunction);
    5163          470859 :     JS_ASSERT_IF(!scope, fun && !script->isInnerFunction);
    5164                 : 
    5165                 :     /*
    5166                 :      * The scope object must be the initial one for the script, before any call
    5167                 :      * object has been created in the heavyweight case.
    5168                 :      */
    5169          623622 :     JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
    5170         1094481 :                  scope->asCall().getCalleeFunction() != fun);
    5171                 : 
    5172          470859 :     if (!script->compileAndGo) {
    5173          315666 :         script->types->global = NULL;
    5174          315666 :         return true;
    5175                 :     }
    5176                 : 
    5177          155193 :     JS_ASSERT_IF(fun && scope, fun->global() == scope->global());
    5178          155193 :     script->types->global = fun ? &fun->global() : &scope->global();
    5179                 : 
    5180                 :     /*
    5181                 :      * Update the parent in the script's bindings. The bindings are created
    5182                 :      * with a NULL parent, and fixing the parent now avoids the need to reshape
    5183                 :      * every time a call object is created from the bindings.
    5184                 :      */
    5185          155193 :     if (!script->bindings.setParent(cx, script->types->global))
    5186               0 :         return false;
    5187                 : 
    5188          155193 :     if (!cx->typeInferenceEnabled())
    5189           74583 :         return true;
    5190                 : 
    5191           80610 :     if (!script->isInnerFunction || nullClosure) {
    5192                 :         /*
    5193                 :          * Outermost functions need nesting information if there are inner
    5194                 :          * functions directly nested in them.
    5195                 :          */
    5196           78228 :         if (script->isOuterFunction) {
    5197            1327 :             script->types->nesting = cx->new_<TypeScriptNesting>();
    5198            1327 :             if (!script->types->nesting)
    5199               0 :                 return false;
    5200                 :         }
    5201           78228 :         return true;
    5202                 :     }
    5203                 : 
    5204                 :     /*
    5205                 :      * Walk the scope chain to the next call object, which will be the function
    5206                 :      * the script is nested inside.
    5207                 :      */
    5208            4869 :     while (!scope->isCall())
    5209             105 :         scope = &scope->asScope().enclosingScope();
    5210                 : 
    5211            2382 :     CallObject &call = scope->asCall();
    5212                 : 
    5213                 :     /* The isInnerFunction test ensures there is no intervening strict eval call object. */
    5214            2382 :     JS_ASSERT(!call.isForEval());
    5215                 : 
    5216                 :     /* Don't track non-heavyweight parents, NAME ops won't reach into them. */
    5217            2382 :     JSFunction *parentFun = call.getCalleeFunction();
    5218            2382 :     if (!parentFun || !parentFun->isHeavyweight())
    5219               0 :         return true;
    5220            2382 :     JSScript *parent = parentFun->script();
    5221            2382 :     JS_ASSERT(parent->isOuterFunction);
    5222                 : 
    5223                 :     /*
    5224                 :      * We only need the nesting in the child if it has NAME accesses going
    5225                 :      * into the parent. We won't know for sure whether this is the case until
    5226                 :      * analyzing the script's types, which we don't want to do yet. The nesting
    5227                 :      * info we make here may get pruned if/when we eventually do such analysis.
    5228                 :      */
    5229                 : 
    5230                 :     /*
    5231                 :      * Scopes are set when scripts first execute, and the parent script must
    5232                 :      * have executed first. It is still possible for the parent script to not
    5233                 :      * have a scope, however, as we occasionally purge all TypeScripts from the
    5234                 :      * compartment and there may be inner function objects parented to an
    5235                 :      * activation of the outer function sticking around. In such cases, treat
    5236                 :      * the parent's call object as the most recent one, so that it is not
    5237                 :      * marked as reentrant.
    5238                 :      */
    5239            2382 :     if (!parent->ensureHasTypes(cx))
    5240               0 :         return false;
    5241            2382 :     if (!parent->types->hasScope()) {
    5242               0 :         if (!SetScope(cx, parent, &call.enclosingScope()))
    5243               0 :             return false;
    5244               0 :         parent->nesting()->activeCall = &call;
    5245               0 :         parent->nesting()->argArray = Valueify(call.argArray());
    5246               0 :         parent->nesting()->varArray = Valueify(call.varArray());
    5247                 :     }
    5248                 : 
    5249            2382 :     JS_ASSERT(!script->types->nesting);
    5250                 : 
    5251                 :     /* Construct and link nesting information for the two functions. */
    5252                 : 
    5253            2382 :     script->types->nesting = cx->new_<TypeScriptNesting>();
    5254            2382 :     if (!script->types->nesting)
    5255               0 :         return false;
    5256                 : 
    5257            2382 :     script->nesting()->parent = parent;
    5258            2382 :     script->nesting()->next = parent->nesting()->children;
    5259            2382 :     parent->nesting()->children = script;
    5260                 : 
    5261            2382 :     return true;
    5262                 : }
    5263                 : 
    5264            3709 : TypeScriptNesting::~TypeScriptNesting()
    5265                 : {
    5266                 :     /*
    5267                 :      * Unlink from any parent/child. Nesting info on a script does not keep
    5268                 :      * either the parent or children live during GC.
    5269                 :      */
    5270                 : 
    5271            3709 :     if (parent) {
    5272            2071 :         JSScript **pscript = &parent->nesting()->children;
    5273            4682 :         while ((*pscript)->nesting() != this)
    5274             540 :             pscript = &(*pscript)->nesting()->next;
    5275            2071 :         *pscript = next;
    5276                 :     }
    5277                 : 
    5278            7543 :     while (children) {
    5279             125 :         TypeScriptNesting *child = children->nesting();
    5280             125 :         children = child->next;
    5281             125 :         child->parent = NULL;
    5282             125 :         child->next = NULL;
    5283                 :     }
    5284            3709 : }
    5285                 : 
    5286                 : bool
    5287          227767 : ClearActiveNesting(JSScript *start)
    5288                 : {
    5289                 :     /*
    5290                 :      * Clear active call information for script and any outer functions
    5291                 :      * inner to it. Return false if an inner function has frames on the stack.
    5292                 :      */
    5293                 : 
    5294                 :     /* Traverse children, then parent, avoiding recursion. */
    5295          227767 :     JSScript *script = start;
    5296          227767 :     bool traverseChildren = true;
    5297          366722 :     while (true) {
    5298          594489 :         TypeScriptNesting *nesting = script->nesting();
    5299          594489 :         if (nesting->children && traverseChildren) {
    5300          202170 :             script = nesting->children;
    5301          202170 :             continue;
    5302                 :         }
    5303          392319 :         if (nesting->activeFrames)
    5304          210488 :             return false;
    5305          181831 :         if (script->isOuterFunction) {
    5306          127954 :             nesting->activeCall = NULL;
    5307          127954 :             nesting->argArray = NULL;
    5308          127954 :             nesting->varArray = NULL;
    5309                 :         }
    5310          181831 :         if (script == start)
    5311                 :             break;
    5312          164552 :         if (nesting->next) {
    5313           40490 :             script = nesting->next;
    5314           40490 :             traverseChildren = true;
    5315                 :         } else {
    5316          124062 :             script = nesting->parent;
    5317          124062 :             traverseChildren = false;
    5318                 :         }
    5319                 :     }
    5320                 : 
    5321           17279 :     return true;
    5322                 : }
    5323                 : 
    5324                 : /*
    5325                 :  * For the specified scope and script with an outer function, check if the
    5326                 :  * scope represents a reentrant activation on an inner function of the parent
    5327                 :  * or any of its transitive parents.
    5328                 :  */
    5329                 : static void
    5330          273208 : CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
    5331                 : {
    5332                 :   restart:
    5333          273208 :     JSScript *parent = script->nesting()->parent;
    5334          273208 :     JS_ASSERT(parent);
    5335                 : 
    5336          594006 :     while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
    5337           47590 :         scope = &scope->asScope().enclosingScope();
    5338                 : 
    5339          273208 :     if (scope != parent->nesting()->activeCall) {
    5340           66935 :         parent->reentrantOuterFunction = true;
    5341           66935 :         MarkTypeObjectFlags(cx, parent->function(), OBJECT_FLAG_REENTRANT_FUNCTION);
    5342                 : 
    5343                 :         /*
    5344                 :          * Continue checking parents to see if this is reentrant for them too.
    5345                 :          * We don't need to check this in for non-reentrant calls on the outer
    5346                 :          * function: when we entered any outer function to the immediate parent
    5347                 :          * we cleared the active call for its transitive children, so a
    5348                 :          * non-reentrant call on a child is also a non-reentrant call on the
    5349                 :          * parent.
    5350                 :          */
    5351           66935 :         if (parent->nesting()->parent) {
    5352           39943 :             scope = &scope->asScope().enclosingScope();
    5353           39943 :             script = parent;
    5354           39943 :             goto restart;
    5355                 :         }
    5356                 :     }
    5357          233265 : }
    5358                 : 
    5359                 : void
    5360          415918 : NestingPrologue(JSContext *cx, StackFrame *fp)
    5361                 : {
    5362          415918 :     JSScript *script = fp->fun()->script();
    5363          415918 :     TypeScriptNesting *nesting = script->nesting();
    5364                 : 
    5365          415918 :     if (nesting->parent)
    5366          233265 :         CheckNestingParent(cx, &fp->scopeChain(), script);
    5367                 : 
    5368          415918 :     if (script->isOuterFunction) {
    5369                 :         /*
    5370                 :          * Check the stack has no frames for this activation, any of its inner
    5371                 :          * functions or any of their transitive inner functions.
    5372                 :          */
    5373          227767 :         if (!ClearActiveNesting(script)) {
    5374          210488 :             script->reentrantOuterFunction = true;
    5375          210488 :             MarkTypeObjectFlags(cx, fp->fun(), OBJECT_FLAG_REENTRANT_FUNCTION);
    5376                 :         }
    5377                 : 
    5378          227767 :         nesting->activeCall = &fp->callObj();
    5379          227767 :         nesting->argArray = fp->formalArgs();
    5380          227767 :         nesting->varArray = fp->slots();
    5381                 :     }
    5382                 : 
    5383                 :     /* Maintain stack frame count for the function. */
    5384          415918 :     nesting->activeFrames++;
    5385          415918 : }
    5386                 : 
    5387                 : void
    5388          320368 : NestingEpilogue(StackFrame *fp)
    5389                 : {
    5390          320368 :     JSScript *script = fp->fun()->script();
    5391          320368 :     TypeScriptNesting *nesting = script->nesting();
    5392                 : 
    5393          320368 :     JS_ASSERT(nesting->activeFrames != 0);
    5394          320368 :     nesting->activeFrames--;
    5395          320368 : }
    5396                 : 
    5397                 : } } /* namespace js::types */
    5398                 : 
    5399                 : /////////////////////////////////////////////////////////////////////
    5400                 : // TypeScript
    5401                 : /////////////////////////////////////////////////////////////////////
    5402                 : 
    5403                 : /*
    5404                 :  * Returns true if we don't expect to compute the correct types for some value
    5405                 :  * pushed by the specified bytecode.
    5406                 :  */
    5407                 : static inline bool
    5408         9917986 : IgnorePushed(const jsbytecode *pc, unsigned index)
    5409                 : {
    5410         9917986 :     switch (JSOp(*pc)) {
    5411                 :       /* We keep track of the scopes pushed by BINDNAME separately. */
    5412                 :       case JSOP_BINDNAME:
    5413                 :       case JSOP_BINDGNAME:
    5414                 :       case JSOP_BINDXMLNAME:
    5415          212490 :         return true;
    5416                 : 
    5417                 :       /* Stack not consistent in TRY_BRANCH_AFTER_COND. */
    5418                 :       case JSOP_IN:
    5419                 :       case JSOP_EQ:
    5420                 :       case JSOP_NE:
    5421                 :       case JSOP_LT:
    5422                 :       case JSOP_LE:
    5423                 :       case JSOP_GT:
    5424                 :       case JSOP_GE:
    5425            4949 :         return (index == 0);
    5426                 : 
    5427                 :       /* Value not determining result is not pushed by OR/AND. */
    5428                 :       case JSOP_OR:
    5429                 :       case JSOP_AND:
    5430            5308 :         return (index == 0);
    5431                 : 
    5432                 :       /* Holes tracked separately. */
    5433                 :       case JSOP_HOLE:
    5434             888 :         return (index == 0);
    5435                 :       case JSOP_FILTER:
    5436               0 :         return (index == 1);
    5437                 : 
    5438                 :       /* Storage for 'with' and 'let' blocks not monitored. */
    5439                 :       case JSOP_ENTERWITH:
    5440                 :       case JSOP_ENTERBLOCK:
    5441                 :       case JSOP_ENTERLET0:
    5442                 :       case JSOP_ENTERLET1:
    5443           37548 :         return true;
    5444                 : 
    5445                 :       /* We don't keep track of the iteration state for 'for in' or 'for each in' loops. */
    5446                 :       case JSOP_ITER:
    5447                 :       case JSOP_ITERNEXT:
    5448                 :       case JSOP_MOREITER:
    5449                 :       case JSOP_ENDITER:
    5450           40084 :         return true;
    5451                 : 
    5452                 :       /* Ops which can manipulate values pushed by opcodes we don't model. */
    5453                 :       case JSOP_DUP:
    5454                 :       case JSOP_DUP2:
    5455                 :       case JSOP_SWAP:
    5456                 :       case JSOP_PICK:
    5457          795564 :         return true;
    5458                 : 
    5459                 :       /* We don't keep track of state indicating whether there is a pending exception. */
    5460                 :       case JSOP_FINALLY:
    5461             600 :         return true;
    5462                 : 
    5463                 :       /*
    5464                 :        * We don't treat GETLOCAL immediately followed by a pop as a use-before-def,
    5465                 :        * and while the type will have been inferred correctly the method JIT
    5466                 :        * may not have written the local's initial undefined value to the stack,
    5467                 :        * leaving a stale value.
    5468                 :        */
    5469                 :       case JSOP_GETLOCAL:
    5470          611952 :         return JSOp(pc[JSOP_GETLOCAL_LENGTH]) == JSOP_POP;
    5471                 : 
    5472                 :       default:
    5473         8208603 :         return false;
    5474                 :     }
    5475                 : }
    5476                 : 
    5477                 : bool
    5478          470919 : JSScript::makeTypes(JSContext *cx)
    5479                 : {
    5480          470919 :     JS_ASSERT(!types);
    5481                 : 
    5482          470919 :     if (!cx->typeInferenceEnabled()) {
    5483          385934 :         types = (TypeScript *) cx->calloc_(sizeof(TypeScript));
    5484          385934 :         if (!types)
    5485               0 :             return false;
    5486          385934 :         new(types) TypeScript();
    5487          385934 :         return true;
    5488                 :     }
    5489                 : 
    5490          169970 :     AutoEnterTypeInference enter(cx);
    5491                 : 
    5492           84985 :     unsigned count = TypeScript::NumTypeSets(this);
    5493                 : 
    5494           84985 :     types = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(TypeSet) * count));
    5495           84985 :     if (!types) {
    5496               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    5497               0 :         return false;
    5498                 :     }
    5499                 : 
    5500           84985 :     new(types) TypeScript();
    5501                 : 
    5502                 : #ifdef DEBUG
    5503           84985 :     TypeSet *typeArray = types->typeArray();
    5504         1280099 :     for (unsigned i = 0; i < nTypeSets; i++)
    5505                 :         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
    5506                 :                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
    5507         1195114 :                   i, id());
    5508           84985 :     TypeSet *returnTypes = TypeScript::ReturnTypes(this);
    5509                 :     InferSpew(ISpewOps, "typeSet: %sT%p%s return #%u",
    5510                 :               InferSpewColor(returnTypes), returnTypes, InferSpewColorReset(),
    5511           84985 :               id());
    5512           84985 :     TypeSet *thisTypes = TypeScript::ThisTypes(this);
    5513                 :     InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
    5514                 :               InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
    5515           84985 :               id());
    5516           84985 :     unsigned nargs = function() ? function()->nargs : 0;
    5517          194002 :     for (unsigned i = 0; i < nargs; i++) {
    5518          109017 :         TypeSet *types = TypeScript::ArgTypes(this, i);
    5519                 :         InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u",
    5520                 :                   InferSpewColor(types), types, InferSpewColorReset(),
    5521          109017 :                   i, id());
    5522                 :     }
    5523          150887 :     for (unsigned i = 0; i < nfixed; i++) {
    5524           65902 :         TypeSet *types = TypeScript::LocalTypes(this, i);
    5525                 :         InferSpew(ISpewOps, "typeSet: %sT%p%s local%u #%u",
    5526                 :                   InferSpewColor(types), types, InferSpewColorReset(),
    5527           65902 :                   i, id());
    5528                 :     }
    5529                 : #endif
    5530                 : 
    5531           84985 :     return true;
    5532                 : }
    5533                 : 
    5534                 : bool
    5535          900984 : JSScript::makeAnalysis(JSContext *cx)
    5536                 : {
    5537          900984 :     JS_ASSERT(types && !types->analysis);
    5538                 : 
    5539         1801968 :     AutoEnterAnalysis enter(cx);
    5540                 : 
    5541          900984 :     types->analysis = cx->typeLifoAlloc().new_<ScriptAnalysis>(this);
    5542                 : 
    5543          900984 :     if (!types->analysis)
    5544               0 :         return false;
    5545                 : 
    5546          900984 :     types->analysis->analyzeBytecode(cx);
    5547                 : 
    5548          900984 :     if (types->analysis->OOM()) {
    5549               0 :         types->analysis = NULL;
    5550               0 :         return false;
    5551                 :     }
    5552                 : 
    5553          900984 :     return true;
    5554                 : }
    5555                 : 
    5556                 : bool
    5557         1164884 : JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
    5558                 : {
    5559         1164884 :     function_ = fun;
    5560                 : 
    5561         1164884 :     if (!cx->typeInferenceEnabled())
    5562         1093795 :         return true;
    5563                 : 
    5564           71089 :     if (singleton) {
    5565           57326 :         if (!fun->setSingletonType(cx))
    5566               0 :             return false;
    5567                 :     } else {
    5568                 :         TypeObject *type = cx->compartment->types.newTypeObject(cx, this,
    5569           13763 :                                                                 JSProto_Function, fun->getProto());
    5570           13763 :         if (!type)
    5571               0 :             return false;
    5572                 : 
    5573           13763 :         fun->setType(type);
    5574           13763 :         type->interpretedFunction = fun;
    5575                 :     }
    5576                 : 
    5577           71089 :     return true;
    5578                 : }
    5579                 : 
    5580                 : #ifdef DEBUG
    5581                 : 
    5582                 : /* static */ void
    5583       859440498 : TypeScript::CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp)
    5584                 : {
    5585      1718880996 :     AutoEnterTypeInference enter(cx);
    5586                 : 
    5587       859440498 :     if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
    5588                 :         return;
    5589                 : 
    5590       857417121 :     if (!script->hasAnalysis() || !script->analysis()->ranInference())
    5591                 :         return;
    5592        11740176 :     ScriptAnalysis *analysis = script->analysis();
    5593                 : 
    5594        11740176 :     int defCount = GetDefCount(script, pc - script->code);
    5595                 : 
    5596        21658162 :     for (int i = 0; i < defCount; i++) {
    5597         9917986 :         const js::Value &val = sp[-defCount + i];
    5598         9917986 :         TypeSet *types = analysis->pushedTypes(pc, i);
    5599         9917986 :         if (IgnorePushed(pc, i))
    5600         1164090 :             continue;
    5601                 : 
    5602         8753896 :         Type type = GetValueType(cx, val);
    5603                 : 
    5604         8753896 :         if (!types->hasType(type)) {
    5605                 :             /* Display fine-grained debug information first */
    5606                 :             fprintf(stderr, "Missing type at #%u:%05u pushed %u: %s\n", 
    5607               0 :                     script->id(), unsigned(pc - script->code), i, TypeString(type));
    5608               0 :             TypeFailure(cx, "Missing type pushed %u: %s", i, TypeString(type));
    5609                 :         }
    5610                 :     }
    5611                 : }
    5612                 : 
    5613                 : #endif
    5614                 : 
    5615                 : /////////////////////////////////////////////////////////////////////
    5616                 : // JSObject
    5617                 : /////////////////////////////////////////////////////////////////////
    5618                 : 
    5619                 : bool
    5620           38637 : JSObject::shouldSplicePrototype(JSContext *cx)
    5621                 : {
    5622                 :     /*
    5623                 :      * During bootstrapping, if inference is enabled we need to make sure not
    5624                 :      * to splice a new prototype in for Function.prototype or the global
    5625                 :      * object if their __proto__ had previously been set to null, as this
    5626                 :      * will change the prototype for all other objects with the same type.
    5627                 :      * If inference is disabled we cannot determine from the object whether it
    5628                 :      * has had its __proto__ set after creation.
    5629                 :      */
    5630           38637 :     if (getProto() != NULL)
    5631              41 :         return false;
    5632           38596 :     return !cx->typeInferenceEnabled() || hasSingletonType();
    5633                 : }
    5634                 : 
    5635                 : bool
    5636           51446 : JSObject::splicePrototype(JSContext *cx, JSObject *proto)
    5637                 : {
    5638                 :     /*
    5639                 :      * For singleton types representing only a single JSObject, the proto
    5640                 :      * can be rearranged as needed without destroying type information for
    5641                 :      * the old or new types. Note that type constraints propagating properties
    5642                 :      * from the old prototype are not removed.
    5643                 :      */
    5644           51446 :     JS_ASSERT_IF(cx->typeInferenceEnabled(), hasSingletonType());
    5645                 : 
    5646                 :     /* Inner objects may not appear on prototype chains. */
    5647           51446 :     JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
    5648                 : 
    5649                 :     /*
    5650                 :      * Force type instantiation when splicing lazy types. This may fail,
    5651                 :      * in which case inference will be disabled for the compartment.
    5652                 :      */
    5653           51446 :     TypeObject *type = getType(cx);
    5654           51446 :     TypeObject *protoType = NULL;
    5655           51446 :     if (proto) {
    5656           51351 :         protoType = proto->getType(cx);
    5657           51351 :         if (!proto->getNewType(cx))
    5658               0 :             return false;
    5659                 :     }
    5660                 : 
    5661           51446 :     if (!cx->typeInferenceEnabled()) {
    5662           25512 :         TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
    5663           25512 :         if (!type)
    5664               0 :             return false;
    5665           25512 :         type_ = type;
    5666           25512 :         return true;
    5667                 :     }
    5668                 : 
    5669           25934 :     type->proto = proto;
    5670                 : 
    5671           51868 :     AutoEnterTypeInference enter(cx);
    5672                 : 
    5673           25934 :     if (protoType && protoType->unknownProperties() && !type->unknownProperties()) {
    5674           12655 :         type->markUnknown(cx);
    5675           12655 :         return true;
    5676                 :     }
    5677                 : 
    5678           13279 :     if (!type->unknownProperties()) {
    5679                 :         /* Update properties on this type with any shared with the prototype. */
    5680           13174 :         unsigned count = type->getPropertyCount();
    5681           13367 :         for (unsigned i = 0; i < count; i++) {
    5682             193 :             Property *prop = type->getProperty(i);
    5683             193 :             if (prop && prop->types.hasPropagatedProperty())
    5684              56 :                 type->getFromPrototypes(cx, prop->id, &prop->types, true);
    5685                 :         }
    5686                 :     }
    5687                 : 
    5688           13279 :     return true;
    5689                 : }
    5690                 : 
    5691                 : void
    5692           51738 : JSObject::makeLazyType(JSContext *cx)
    5693                 : {
    5694           51738 :     JS_ASSERT(cx->typeInferenceEnabled() && hasLazyType());
    5695          103476 :     AutoEnterTypeInference enter(cx);
    5696                 : 
    5697                 :     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
    5698           51738 :                                                             JSProto_Object, getProto());
    5699           51738 :     if (!type) {
    5700               0 :         cx->compartment->types.setPendingNukeTypes(cx);
    5701                 :         return;
    5702                 :     }
    5703                 : 
    5704                 :     /* Fill in the type according to the state of this object. */
    5705                 : 
    5706           51738 :     type->singleton = this;
    5707                 : 
    5708           51738 :     if (isFunction() && toFunction()->isInterpreted()) {
    5709            7470 :         type->interpretedFunction = toFunction();
    5710            7470 :         JSScript *script = type->interpretedFunction->script();
    5711            7470 :         if (script->createdArgs)
    5712               9 :             type->flags |= OBJECT_FLAG_CREATED_ARGUMENTS;
    5713            7470 :         if (script->uninlineable)
    5714             193 :             type->flags |= OBJECT_FLAG_UNINLINEABLE;
    5715            7470 :         if (script->reentrantOuterFunction)
    5716               6 :             type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION;
    5717                 :     }
    5718                 : 
    5719           51738 :     if (lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
    5720               3 :         type->flags |= OBJECT_FLAG_ITERATED;
    5721                 : 
    5722                 : #if JS_HAS_XML_SUPPORT
    5723                 :     /*
    5724                 :      * XML objects do not have equality hooks but are treated special by EQ/NE
    5725                 :      * ops. Just mark the type as totally unknown.
    5726                 :      */
    5727           51738 :     if (isXML() && !type->unknownProperties())
    5728               0 :         type->markUnknown(cx);
    5729                 : #endif
    5730                 : 
    5731           51738 :     if (getClass()->ext.equality)
    5732               2 :         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
    5733                 : 
    5734           51738 :     if (type->unknownProperties()) {
    5735               0 :         type_ = type;
    5736                 :         return;
    5737                 :     }
    5738                 : 
    5739                 :     /* Not yet generating singleton arrays. */
    5740                 :     type->flags |= OBJECT_FLAG_NON_DENSE_ARRAY
    5741                 :                 |  OBJECT_FLAG_NON_PACKED_ARRAY
    5742           51738 :                 |  OBJECT_FLAG_NON_TYPED_ARRAY;
    5743                 : 
    5744           51738 :     type_ = type;
    5745                 : }
    5746                 : 
    5747                 : /* static */ inline HashNumber
    5748        27821192 : TypeObjectEntry::hash(JSObject *proto)
    5749                 : {
    5750        27821192 :     return PointerHasher<JSObject *, 3>::hash(proto);
    5751                 : }
    5752                 : 
    5753                 : /* static */ inline bool
    5754        26866617 : TypeObjectEntry::match(TypeObject *key, JSObject *lookup)
    5755                 : {
    5756        26866617 :     return key->proto == lookup;
    5757                 : }
    5758                 : 
    5759                 : #ifdef DEBUG
    5760                 : bool
    5761         2799530 : JSObject::hasNewType(TypeObject *type)
    5762                 : {
    5763         2799530 :     TypeObjectSet &table = compartment()->newTypeObjects;
    5764                 : 
    5765         2799530 :     if (!table.initialized())
    5766               0 :         return false;
    5767                 : 
    5768         2799530 :     TypeObjectSet::Ptr p = table.lookup(this);
    5769         2799530 :     return p && *p == type;
    5770                 : }
    5771                 : #endif /* DEBUG */
    5772                 : 
    5773                 : bool
    5774         3310818 : JSObject::setNewTypeUnknown(JSContext *cx)
    5775                 : {
    5776         3310818 :     if (!setFlag(cx, js::BaseShape::NEW_TYPE_UNKNOWN))
    5777               0 :         return false;
    5778                 : 
    5779                 :     /*
    5780                 :      * If the object already has a new type, mark that type as unknown. It will
    5781                 :      * not have the SETS_MARKED_UNKNOWN bit set, so may require a type set
    5782                 :      * crawl if prototypes of the object change dynamically in the future.
    5783                 :      */
    5784         3310818 :     TypeObjectSet &table = cx->compartment->newTypeObjects;
    5785         3310818 :     if (table.initialized()) {
    5786         3285171 :         if (TypeObjectSet::Ptr p = table.lookup(this))
    5787         2894450 :             MarkTypeObjectUnknownProperties(cx, *p);
    5788                 :     }
    5789                 : 
    5790         3310818 :     return true;
    5791                 : }
    5792                 : 
    5793                 : TypeObject *
    5794        17796889 : JSObject::getNewType(JSContext *cx, JSFunction *fun)
    5795                 : {
    5796        17796889 :     TypeObjectSet &table = cx->compartment->newTypeObjects;
    5797                 : 
    5798        17796889 :     if (!table.initialized() && !table.init())
    5799               0 :         return NULL;
    5800                 : 
    5801        17796889 :     TypeObjectSet::AddPtr p = table.lookupForAdd(this);
    5802        17796889 :     if (p) {
    5803        17274637 :         TypeObject *type = *p;
    5804                 : 
    5805                 :         /*
    5806                 :          * If set, the type's newScript indicates the script used to create
    5807                 :          * all objects in existence which have this type. If there are objects
    5808                 :          * in existence which are not created by calling 'new' on newScript,
    5809                 :          * we must clear the new script information from the type and will not
    5810                 :          * be able to assume any definite properties for instances of the type.
    5811                 :          * This case is rare, but can happen if, for example, two scripted
    5812                 :          * functions have the same value for their 'prototype' property, or if
    5813                 :          * Object.create is called with a prototype object that is also the
    5814                 :          * 'prototype' property of some scripted function.
    5815                 :          */
    5816        17274637 :         if (type->newScript && type->newScript->fun != fun)
    5817              10 :             type->clearNewScript(cx);
    5818                 : 
    5819        17274637 :         return type;
    5820                 :     }
    5821                 : 
    5822         1044504 :     RootedVarObject self(cx, this);
    5823                 : 
    5824          522252 :     if (!setDelegate(cx))
    5825               0 :         return NULL;
    5826                 : 
    5827          522252 :     bool markUnknown = self->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN);
    5828                 : 
    5829                 :     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
    5830          522252 :                                                             JSProto_Object, self, markUnknown);
    5831          522252 :     if (!type)
    5832               0 :         return NULL;
    5833                 : 
    5834          522252 :     if (!table.relookupOrAdd(p, self, type))
    5835               0 :         return NULL;
    5836                 : 
    5837          522252 :     if (!cx->typeInferenceEnabled())
    5838          409525 :         return type;
    5839                 : 
    5840          225454 :     AutoEnterTypeInference enter(cx);
    5841                 : 
    5842                 :     /*
    5843                 :      * Set the special equality flag for types whose prototype also has the
    5844                 :      * flag set. This is a hack, :XXX: need a real correspondence between
    5845                 :      * types and the possible js::Class of objects with that type.
    5846                 :      */
    5847          112727 :     if (self->hasSpecialEquality())
    5848             395 :         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
    5849                 : 
    5850          112727 :     if (fun)
    5851            1465 :         CheckNewScriptProperties(cx, type, fun);
    5852                 : 
    5853                 : #if JS_HAS_XML_SUPPORT
    5854                 :     /* Special case for XML object equality, see makeLazyType(). */
    5855          112727 :     if (self->isXML() && !type->unknownProperties())
    5856             210 :         type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
    5857                 : #endif
    5858                 : 
    5859          112727 :     if (self->getClass()->ext.equality)
    5860             395 :         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
    5861                 : 
    5862                 :     /*
    5863                 :      * The new type is not present in any type sets, so mark the object as
    5864                 :      * unknown in all type sets it appears in. This allows the prototype of
    5865                 :      * such objects to mutate freely without triggering an expensive walk of
    5866                 :      * the compartment's type sets. (While scripts normally don't mutate
    5867                 :      * __proto__, the browser will for proxies and such, and we need to
    5868                 :      * accommodate this behavior).
    5869                 :      */
    5870          112727 :     if (type->unknownProperties())
    5871           84548 :         type->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
    5872                 : 
    5873          112727 :     return type;
    5874                 : }
    5875                 : 
    5876                 : TypeObject *
    5877         3939602 : JSCompartment::getLazyType(JSContext *cx, JSObject *proto)
    5878                 : {
    5879         3939602 :     gc::MaybeCheckStackRoots(cx);
    5880                 : 
    5881         3939602 :     TypeObjectSet &table = cx->compartment->lazyTypeObjects;
    5882                 : 
    5883         3939602 :     if (!table.initialized() && !table.init())
    5884               0 :         return NULL;
    5885                 : 
    5886         3939602 :     TypeObjectSet::AddPtr p = table.lookupForAdd(proto);
    5887         3939602 :     if (p) {
    5888         3898000 :         TypeObject *type = *p;
    5889         3898000 :         JS_ASSERT(type->lazy());
    5890                 : 
    5891         3898000 :         return type;
    5892                 :     }
    5893                 : 
    5894                 :     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
    5895           41602 :                                                             JSProto_Object, proto, false);
    5896           41602 :     if (!type)
    5897               0 :         return NULL;
    5898                 : 
    5899           41602 :     if (!table.relookupOrAdd(p, proto, type))
    5900               0 :         return NULL;
    5901                 : 
    5902           41602 :     type->singleton = (JSObject *) TypeObject::LAZY_SINGLETON;
    5903                 : 
    5904           41602 :     return type;
    5905                 : }
    5906                 : 
    5907                 : /////////////////////////////////////////////////////////////////////
    5908                 : // Tracing
    5909                 : /////////////////////////////////////////////////////////////////////
    5910                 : 
    5911                 : void
    5912         1739670 : TypeSet::sweep(JSContext *cx, JSCompartment *compartment)
    5913                 : {
    5914                 :     /*
    5915                 :      * Purge references to type objects that are no longer live. Type sets hold
    5916                 :      * only weak references. For type sets containing more than one object,
    5917                 :      * live entries in the object hash need to be copied to the compartment's
    5918                 :      * new arena.
    5919                 :      */
    5920         1739670 :     unsigned objectCount = baseObjectCount();
    5921         1739670 :     if (objectCount >= 2) {
    5922           10124 :         unsigned oldCapacity = HashSetCapacity(objectCount);
    5923           10124 :         TypeObjectKey **oldArray = objectSet;
    5924                 : 
    5925           10124 :         clearObjects();
    5926           10124 :         objectCount = 0;
    5927          975972 :         for (unsigned i = 0; i < oldCapacity; i++) {
    5928          965848 :             TypeObjectKey *object = oldArray[i];
    5929          965848 :             if (object && !IsAboutToBeFinalized(object)) {
    5930                 :                 TypeObjectKey **pentry =
    5931                 :                     HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
    5932          305385 :                         (compartment, objectSet, objectCount, object);
    5933          305385 :                 if (pentry)
    5934          305385 :                     *pentry = object;
    5935                 :                 else
    5936               0 :                     compartment->types.setPendingNukeTypes(cx);
    5937                 :             }
    5938                 :         }
    5939           10124 :         setBaseObjectCount(objectCount);
    5940         1729546 :     } else if (objectCount == 1) {
    5941          337778 :         TypeObjectKey *object = (TypeObjectKey *) objectSet;
    5942          337778 :         if (IsAboutToBeFinalized(object)) {
    5943          260566 :             objectSet = NULL;
    5944          260566 :             setBaseObjectCount(0);
    5945                 :         }
    5946                 :     }
    5947                 : 
    5948                 :     /*
    5949                 :      * All constraints are wiped out on each GC, including those propagating
    5950                 :      * into this type set from prototype properties.
    5951                 :      */
    5952         1739670 :     constraintList = NULL;
    5953         1739670 :     flags &= ~TYPE_FLAG_PROPAGATED_PROPERTY;
    5954         1739670 : }
    5955                 : 
    5956                 : inline void
    5957          196010 : TypeObject::clearProperties()
    5958                 : {
    5959          196010 :     setBasePropertyCount(0);
    5960          196010 :     propertySet = NULL;
    5961          196010 : }
    5962                 : 
    5963                 : /*
    5964                 :  * Before sweeping the arenas themselves, scan all type objects in a
    5965                 :  * compartment to fixup weak references: property type sets referencing dead
    5966                 :  * JS and type objects, and singleton JS objects whose type is not referenced
    5967                 :  * elsewhere. This also releases memory associated with dead type objects,
    5968                 :  * so that type objects do not need later finalization.
    5969                 :  */
    5970                 : inline void
    5971         2771102 : TypeObject::sweep(JSContext *cx)
    5972                 : {
    5973                 :     /*
    5974                 :      * We may be regenerating existing type sets containing this object,
    5975                 :      * so reset contributions on each GC to avoid tripping the limit.
    5976                 :      */
    5977         2771102 :     contribution = 0;
    5978                 : 
    5979         2771102 :     if (singleton) {
    5980          195122 :         JS_ASSERT(!newScript);
    5981                 : 
    5982                 :         /*
    5983                 :          * All properties can be discarded. We will regenerate them as needed
    5984                 :          * as code gets reanalyzed.
    5985                 :          */
    5986          195122 :         clearProperties();
    5987                 : 
    5988          195122 :         return;
    5989                 :     }
    5990                 : 
    5991         2575980 :     if (!isMarked()) {
    5992          577646 :         if (newScript)
    5993             540 :             Foreground::free_(newScript);
    5994          577646 :         return;
    5995                 :     }
    5996                 : 
    5997         1998334 :     JSCompartment *compartment = this->compartment();
    5998                 : 
    5999                 :     /*
    6000                 :      * Properties were allocated from the old arena, and need to be copied over
    6001                 :      * to the new one. Don't hang onto properties without the OWN_PROPERTY
    6002                 :      * flag; these were never directly assigned, and get any possible values
    6003                 :      * from the object's prototype.
    6004                 :      */
    6005         1998334 :     unsigned propertyCount = basePropertyCount();
    6006         1998334 :     if (propertyCount >= 2) {
    6007             888 :         unsigned oldCapacity = HashSetCapacity(propertyCount);
    6008             888 :         Property **oldArray = propertySet;
    6009                 : 
    6010             888 :         clearProperties();
    6011             888 :         propertyCount = 0;
    6012            9112 :         for (unsigned i = 0; i < oldCapacity; i++) {
    6013            8224 :             Property *prop = oldArray[i];
    6014            8224 :             if (prop && prop->types.isOwnProperty(false)) {
    6015            2992 :                 Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop);
    6016            2992 :                 if (newProp) {
    6017                 :                     Property **pentry =
    6018                 :                         HashSetInsert<jsid,Property,Property>
    6019            2992 :                             (compartment, propertySet, propertyCount, prop->id);
    6020            2992 :                     if (pentry) {
    6021            2992 :                         *pentry = newProp;
    6022            2992 :                         newProp->types.sweep(cx, compartment);
    6023                 :                     } else {
    6024               0 :                         compartment->types.setPendingNukeTypes(cx);
    6025                 :                     }
    6026                 :                 } else {
    6027               0 :                     compartment->types.setPendingNukeTypes(cx);
    6028                 :                 }
    6029                 :             }
    6030                 :         }
    6031             888 :         setBasePropertyCount(propertyCount);
    6032         1997446 :     } else if (propertyCount == 1) {
    6033            1907 :         Property *prop = (Property *) propertySet;
    6034            1907 :         if (prop->types.isOwnProperty(false)) {
    6035            1788 :             Property *newProp = compartment->typeLifoAlloc.new_<Property>(*prop);
    6036            1788 :             if (newProp) {
    6037            1788 :                 propertySet = (Property **) newProp;
    6038            1788 :                 newProp->types.sweep(cx, compartment);
    6039                 :             } else {
    6040               0 :                 compartment->types.setPendingNukeTypes(cx);
    6041                 :             }
    6042                 :         } else {
    6043             119 :             propertySet = NULL;
    6044             119 :             setBasePropertyCount(0);
    6045                 :         }
    6046                 :     }
    6047                 : 
    6048         1998334 :     if (basePropertyCount() <= SET_ARRAY_SIZE) {
    6049         2002759 :         for (unsigned i = 0; i < basePropertyCount(); i++)
    6050            4445 :             JS_ASSERT(propertySet[i]);
    6051                 :     }
    6052                 : 
    6053                 :     /*
    6054                 :      * The GC will clear out the constraints ensuring the correctness of the
    6055                 :      * newScript information, these constraints will need to be regenerated
    6056                 :      * the next time we compile code which depends on this info.
    6057                 :      */
    6058         1998334 :     if (newScript)
    6059               9 :         flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
    6060                 : }
    6061                 : 
    6062                 : struct SweepTypeObjectOp
    6063                 : {
    6064                 :     JSContext *cx;
    6065          122442 :     SweepTypeObjectOp(JSContext *cx) : cx(cx) {}
    6066         2771102 :     void operator()(gc::Cell *cell) {
    6067         2771102 :         TypeObject *object = static_cast<TypeObject *>(cell);
    6068         2771102 :         object->sweep(cx);
    6069         2771102 :     }
    6070                 : };
    6071                 : 
    6072                 : void
    6073          122442 : SweepTypeObjects(JSContext *cx, JSCompartment *compartment)
    6074                 : {
    6075          122442 :     SweepTypeObjectOp op(cx);
    6076          122442 :     gc::ForEachArenaAndCell(compartment, gc::FINALIZE_TYPE_OBJECT, gc::EmptyArenaOp, op);
    6077          122442 : }
    6078                 : 
    6079                 : void
    6080          122442 : TypeCompartment::sweep(JSContext *cx)
    6081                 : {
    6082          122442 :     JSCompartment *compartment = this->compartment();
    6083                 : 
    6084          122442 :     SweepTypeObjects(cx, compartment);
    6085                 : 
    6086                 :     /*
    6087                 :      * Iterate through the array/object type tables and remove all entries
    6088                 :      * referencing collected data. These tables only hold weak references.
    6089                 :      */
    6090                 : 
    6091          122442 :     if (arrayTypeTable) {
    6092            1582 :         for (ArrayTypeTable::Enum e(*arrayTypeTable); !e.empty(); e.popFront()) {
    6093             833 :             const ArrayTableKey &key = e.front().key;
    6094             833 :             TypeObject *obj = e.front().value;
    6095             833 :             JS_ASSERT(obj->proto == key.proto);
    6096             833 :             JS_ASSERT(!key.type.isSingleObject());
    6097                 : 
    6098             833 :             bool remove = false;
    6099             833 :             if (key.type.isTypeObject() && !key.type.typeObject()->isMarked())
    6100              50 :                 remove = true;
    6101             833 :             if (!obj->isMarked())
    6102             825 :                 remove = true;
    6103                 : 
    6104             833 :             if (remove)
    6105             825 :                 e.removeFront();
    6106                 :         }
    6107                 :     }
    6108                 : 
    6109          122442 :     if (objectTypeTable) {
    6110            1388 :         for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
    6111             816 :             const ObjectTableKey &key = e.front().key;
    6112             816 :             const ObjectTableEntry &entry = e.front().value;
    6113             816 :             JS_ASSERT(entry.object->proto == key.proto);
    6114                 : 
    6115             816 :             bool remove = false;
    6116             816 :             if (!entry.object->isMarked())
    6117             763 :                 remove = true;
    6118             897 :             for (unsigned i = 0; !remove && i < key.nslots; i++) {
    6119              81 :                 if (JSID_IS_STRING(key.ids[i])) {
    6120              81 :                     JSString *str = JSID_TO_STRING(key.ids[i]);
    6121              81 :                     if (!str->isMarked())
    6122               0 :                         remove = true;
    6123                 :                 }
    6124              81 :                 JS_ASSERT(!entry.types[i].isSingleObject());
    6125              81 :                 if (entry.types[i].isTypeObject() && !entry.types[i].typeObject()->isMarked())
    6126               0 :                     remove = true;
    6127                 :             }
    6128                 : 
    6129             816 :             if (remove) {
    6130             763 :                 Foreground::free_(key.ids);
    6131             763 :                 Foreground::free_(entry.types);
    6132             763 :                 e.removeFront();
    6133                 :             }
    6134                 :         }
    6135                 :     }
    6136                 : 
    6137          122442 :     if (allocationSiteTable) {
    6138           24706 :         for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) {
    6139           17599 :             const AllocationSiteKey &key = e.front().key;
    6140           17599 :             TypeObject *object = e.front().value;
    6141                 : 
    6142           17599 :             if (IsAboutToBeFinalized(key.script) || !object->isMarked())
    6143           14532 :                 e.removeFront();
    6144                 :         }
    6145                 :     }
    6146                 : 
    6147                 :     /*
    6148                 :      * The pending array is reset on GC, it can grow large (75+ KB) and is easy
    6149                 :      * to reallocate if the compartment becomes active again.
    6150                 :      */
    6151          122442 :     if (pendingArray)
    6152            7517 :         cx->free_(pendingArray);
    6153                 : 
    6154          122442 :     pendingArray = NULL;
    6155          122442 :     pendingCapacity = 0;
    6156          122442 : }
    6157                 : 
    6158                 : void
    6159          244956 : JSCompartment::sweepNewTypeObjectTable(JSContext *cx, TypeObjectSet &table)
    6160                 : {
    6161          244956 :     if (table.initialized()) {
    6162         2650069 :         for (TypeObjectSet::Enum e(table); !e.empty(); e.popFront()) {
    6163         2554892 :             TypeObject *type = e.front();
    6164         2554892 :             if (!type->isMarked())
    6165          563712 :                 e.removeFront();
    6166                 :         }
    6167                 :     }
    6168          244956 : }
    6169                 : 
    6170           45571 : TypeCompartment::~TypeCompartment()
    6171                 : {
    6172           45571 :     if (pendingArray)
    6173               0 :         Foreground::free_(pendingArray);
    6174                 : 
    6175           45571 :     if (arrayTypeTable)
    6176             745 :         Foreground::delete_(arrayTypeTable);
    6177                 : 
    6178           45571 :     if (objectTypeTable)
    6179             538 :         Foreground::delete_(objectTypeTable);
    6180                 : 
    6181           45571 :     if (allocationSiteTable)
    6182            5008 :         Foreground::delete_(allocationSiteTable);
    6183           45571 : }
    6184                 : 
    6185                 : /* static */ void
    6186          114034 : TypeScript::Sweep(JSContext *cx, JSScript *script)
    6187                 : {
    6188          114034 :     JSCompartment *compartment = script->compartment();
    6189          114034 :     JS_ASSERT(compartment->types.inferenceEnabled);
    6190                 : 
    6191          114034 :     unsigned num = NumTypeSets(script);
    6192          114034 :     TypeSet *typeArray = script->types->typeArray();
    6193                 : 
    6194                 :     /* Remove constraints and references to dead objects from the persistent type sets. */
    6195         1848924 :     for (unsigned i = 0; i < num; i++)
    6196         1734890 :         typeArray[i].sweep(cx, compartment);
    6197                 : 
    6198          114034 :     TypeResult **presult = &script->types->dynamicList;
    6199          232306 :     while (*presult) {
    6200            4238 :         TypeResult *result = *presult;
    6201            4238 :         Type type = result->type;
    6202                 : 
    6203            4238 :         if (!type.isUnknown() && !type.isAnyObject() && type.isObject() &&
    6204               0 :             IsAboutToBeFinalized(type.objectKey())) {
    6205               0 :             *presult = result->next;
    6206               0 :             cx->delete_(result);
    6207                 :         } else {
    6208            4238 :             presult = &result->next;
    6209                 :         }
    6210                 :     }
    6211                 : 
    6212                 :     /*
    6213                 :      * If the script has nesting state with a most recent activation, we do not
    6214                 :      * need either to mark the call object or clear it if not live. Even with
    6215                 :      * a dead pointer in the nesting, we can't get a spurious match while
    6216                 :      * testing for reentrancy: if previous activations are still live, they
    6217                 :      * cannot alias the most recent one, and future activations will overwrite
    6218                 :      * activeCall on creation.
    6219                 :      */
    6220          114034 : }
    6221                 : 
    6222                 : void
    6223          470730 : TypeScript::destroy()
    6224                 : {
    6225          944258 :     while (dynamicList) {
    6226            2798 :         TypeResult *next = dynamicList->next;
    6227            2798 :         Foreground::delete_(dynamicList);
    6228            2798 :         dynamicList = next;
    6229                 :     }
    6230                 : 
    6231          470730 :     if (nesting)
    6232            3531 :         Foreground::delete_(nesting);
    6233                 : 
    6234          470730 :     Foreground::free_(this);
    6235          470730 : }
    6236                 : 
    6237                 : inline size_t
    6238               0 : TypeSet::computedSizeOfExcludingThis()
    6239                 : {
    6240                 :     /*
    6241                 :      * This memory is allocated within the temp pool (but accounted for
    6242                 :      * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
    6243                 :      * compute its size analytically.
    6244                 :      */
    6245               0 :     uint32_t count = baseObjectCount();
    6246               0 :     if (count >= 2)
    6247               0 :         return HashSetCapacity(count) * sizeof(TypeObject *);
    6248               0 :     return 0;
    6249                 : }
    6250                 : 
    6251                 : inline size_t
    6252             851 : TypeObject::computedSizeOfExcludingThis()
    6253                 : {
    6254                 :     /*
    6255                 :      * This memory is allocated within the temp pool (but accounted for
    6256                 :      * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
    6257                 :      * compute its size analytically.
    6258                 :      */
    6259             851 :     size_t bytes = 0;
    6260                 : 
    6261             851 :     uint32_t count = basePropertyCount();
    6262             851 :     if (count >= 2)
    6263               0 :         bytes += HashSetCapacity(count) * sizeof(TypeObject *);
    6264                 : 
    6265             851 :     count = getPropertyCount();
    6266             851 :     for (unsigned i = 0; i < count; i++) {
    6267               0 :         Property *prop = getProperty(i);
    6268               0 :         if (prop)
    6269               0 :             bytes += sizeof(Property) + prop->types.computedSizeOfExcludingThis();
    6270                 :     }
    6271                 : 
    6272             851 :     return bytes;
    6273                 : }
    6274                 : 
    6275                 : static void
    6276            3818 : SizeOfScriptTypeInferenceData(JSScript *script, TypeInferenceSizes *sizes,
    6277                 :                               JSMallocSizeOfFun mallocSizeOf)
    6278                 : {
    6279            3818 :     TypeScript *typeScript = script->types;
    6280            3818 :     if (!typeScript)
    6281            2913 :         return;
    6282                 : 
    6283                 :     /* If TI is disabled, a single TypeScript is still present. */
    6284             905 :     if (!script->compartment()->types.inferenceEnabled) {
    6285             905 :         sizes->scripts += mallocSizeOf(typeScript);
    6286             905 :         return;
    6287                 :     }
    6288                 : 
    6289               0 :     sizes->scripts += mallocSizeOf(typeScript->nesting);
    6290                 : 
    6291               0 :     unsigned count = TypeScript::NumTypeSets(script);
    6292               0 :     sizes->scripts += mallocSizeOf(typeScript);
    6293                 : 
    6294               0 :     TypeResult *result = typeScript->dynamicList;
    6295               0 :     while (result) {
    6296               0 :         sizes->scripts += mallocSizeOf(result);
    6297               0 :         result = result->next;
    6298                 :     }
    6299                 : 
    6300                 :     /*
    6301                 :      * This counts memory that is in the temp pool but gets attributed
    6302                 :      * elsewhere.  See JS::SizeOfCompartmentTypeInferenceData for more details.
    6303                 :      */
    6304               0 :     TypeSet *typeArray = typeScript->typeArray();
    6305               0 :     for (unsigned i = 0; i < count; i++) {
    6306               0 :         size_t bytes = typeArray[i].computedSizeOfExcludingThis();
    6307               0 :         sizes->scripts += bytes;
    6308               0 :         sizes->temporary -= bytes;
    6309                 :     }
    6310                 : }
    6311                 : 
    6312                 : void
    6313               9 : JSCompartment::sizeOfTypeInferenceData(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
    6314                 : {
    6315                 :     /*
    6316                 :      * Note: not all data in the pool is temporary, and some will survive GCs
    6317                 :      * by being copied to the replacement pool. This memory will be counted
    6318                 :      * elsewhere and deducted from the amount of temporary data.
    6319                 :      */
    6320               9 :     sizes->temporary += typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
    6321                 : 
    6322                 :     /* Pending arrays are cleared on GC along with the analysis pool. */
    6323               9 :     sizes->temporary += mallocSizeOf(types.pendingArray);
    6324                 : 
    6325                 :     /* TypeCompartment::pendingRecompiles is non-NULL only while inference code is running. */
    6326               9 :     JS_ASSERT(!types.pendingRecompiles);
    6327                 : 
    6328            3827 :     for (gc::CellIter i(this, gc::FINALIZE_SCRIPT); !i.done(); i.next())
    6329            3818 :         SizeOfScriptTypeInferenceData(i.get<JSScript>(), sizes, mallocSizeOf);
    6330                 : 
    6331               9 :     if (types.allocationSiteTable)
    6332               0 :         sizes->tables += types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
    6333                 : 
    6334               9 :     if (types.arrayTypeTable)
    6335               0 :         sizes->tables += types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
    6336                 : 
    6337               9 :     if (types.objectTypeTable) {
    6338               0 :         sizes->tables += types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
    6339                 : 
    6340               0 :         for (ObjectTypeTable::Enum e(*types.objectTypeTable);
    6341               0 :              !e.empty();
    6342               0 :              e.popFront())
    6343                 :         {
    6344               0 :             const ObjectTableKey &key = e.front().key;
    6345               0 :             const ObjectTableEntry &value = e.front().value;
    6346                 : 
    6347                 :             /* key.ids and values.types have the same length. */
    6348               0 :             sizes->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
    6349                 :         }
    6350                 :     }
    6351               9 : }
    6352                 : 
    6353                 : void
    6354             851 : TypeObject::sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
    6355                 : {
    6356             851 :     if (singleton) {
    6357                 :         /*
    6358                 :          * Properties and associated type sets for singletons are cleared on
    6359                 :          * every GC. The type object is normally destroyed too, but we don't
    6360                 :          * charge this to 'temporary' as this is not for GC heap values.
    6361                 :          */
    6362               0 :         JS_ASSERT(!newScript);
    6363               0 :         return;
    6364                 :     }
    6365                 : 
    6366             851 :     sizes->objects += mallocSizeOf(newScript);
    6367                 : 
    6368                 :     /*
    6369                 :      * This counts memory that is in the temp pool but gets attributed
    6370                 :      * elsewhere.  See JSCompartment::sizeOfTypeInferenceData for more details.
    6371                 :      */
    6372             851 :     size_t bytes = computedSizeOfExcludingThis();
    6373             851 :     sizes->objects += bytes;
    6374             851 :     sizes->temporary -= bytes;
    6375                 : }

Generated by: LCOV version 1.7