LCOV - app.info - js/src/jsinfer.cpp

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