LCOV - code coverage report
Current view: directory - js/src - jsinfer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2741 2226 81.2 %
Date: 2012-04-07 Functions: 192 175 91.1 %

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

Generated by: LCOV version 1.7