LCOV - code coverage report
Current view: directory - js/src - jsanalyze.h (source / functions) Found Hit Coverage
Test: app.info Lines: 371 355 95.7 %
Date: 2012-04-07 Functions: 116 113 97.4 %

       1                 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
       2                 : /* vim: set ts=40 sw=4 et tw=99: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is the Mozilla SpiderMonkey bytecode analysis
      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                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /* Definitions for javascript analysis. */
      40                 : 
      41                 : #ifndef jsanalyze_h___
      42                 : #define jsanalyze_h___
      43                 : 
      44                 : #include "jsautooplen.h"
      45                 : #include "jscompartment.h"
      46                 : #include "jscntxt.h"
      47                 : #include "jsinfer.h"
      48                 : #include "jsscript.h"
      49                 : 
      50                 : #include "ds/LifoAlloc.h"
      51                 : #include "js/TemplateLib.h"
      52                 : 
      53                 : struct JSScript;
      54                 : 
      55                 : /* Forward declaration of downstream register allocations computed for join points. */
      56                 : namespace js { namespace mjit { struct RegisterAllocation; } }
      57                 : 
      58                 : namespace js {
      59                 : namespace analyze {
      60                 : 
      61                 : /*
      62                 :  * There are three analyses we can perform on a JSScript, outlined below.
      63                 :  * The results of all three are stored in ScriptAnalysis, but the analyses
      64                 :  * themselves can be performed separately. Along with type inference results,
      65                 :  * per-script analysis results are tied to the per-compartment analysis pool
      66                 :  * and are freed on every garbage collection.
      67                 :  *
      68                 :  * - Basic bytecode analysis. For each bytecode, determine the stack depth at
      69                 :  * that point and control flow information needed for compilation. Also does
      70                 :  * a defined-variables analysis to look for local variables which have uses
      71                 :  * before definitions.
      72                 :  *
      73                 :  * - Lifetime analysis. Makes a backwards pass over the script to approximate
      74                 :  * the regions where each variable is live, avoiding a full fixpointing
      75                 :  * live-variables pass. This is based on the algorithm described in:
      76                 :  *
      77                 :  *     "Quality and Speed in Linear-scan Register Allocation"
      78                 :  *     Traub et. al.
      79                 :  *     PLDI, 1998
      80                 :  *
      81                 :  * - SSA analysis of the script's variables and stack values. For each stack
      82                 :  * value popped and non-escaping local variable or argument read, determines
      83                 :  * which push(es) or write(s) produced that value.
      84                 :  *
      85                 :  * Intermediate type inference results are additionally stored here. The above
      86                 :  * analyses are independent from type inference.
      87                 :  */
      88                 : 
      89                 : /* Information about a bytecode instruction. */
      90                 : class Bytecode
      91                 : {
      92                 :     friend class ScriptAnalysis;
      93                 : 
      94                 :   public:
      95         9170109 :     Bytecode() { PodZero(this); }
      96                 : 
      97                 :     /* --------- Bytecode analysis --------- */
      98                 : 
      99                 :     /* Whether there are any incoming jumps to this instruction. */
     100                 :     bool jumpTarget : 1;
     101                 : 
     102                 :     /* Whether there is fallthrough to this instruction from a non-branching instruction. */
     103                 :     bool fallthrough : 1;
     104                 : 
     105                 :     /* Whether this instruction is the fall through point of a conditional jump. */
     106                 :     bool jumpFallthrough : 1;
     107                 : 
     108                 :     /* Whether this instruction can be branched to from a switch statement. Implies jumpTarget. */
     109                 :     bool switchTarget : 1;
     110                 : 
     111                 :     /*
     112                 :      * Whether this instruction must always execute, unless the script throws
     113                 :      * an exception which it does not later catch.
     114                 :      */
     115                 :     bool unconditional : 1;
     116                 : 
     117                 :     /* Whether this instruction has been analyzed to get its output defines and stack. */
     118                 :     bool analyzed : 1;
     119                 : 
     120                 :     /* Whether this is a catch/finally entry point. */
     121                 :     bool exceptionEntry : 1;
     122                 : 
     123                 :     /* Whether this is in a try block. */
     124                 :     bool inTryBlock : 1;
     125                 : 
     126                 :     /* Whether this is in a loop. */
     127                 :     bool inLoop : 1;
     128                 : 
     129                 :     /* Method JIT safe point. */
     130                 :     bool safePoint : 1;
     131                 : 
     132                 :     /*
     133                 :      * Side effects of this bytecode were not determined by type inference.
     134                 :      * Either a property set with unknown lvalue, or call with unknown callee.
     135                 :      */
     136                 :     bool monitoredTypes : 1;
     137                 : 
     138                 :     /* Call whose result should be monitored. */
     139                 :     bool monitoredTypesReturn : 1;
     140                 : 
     141                 :     /*
     142                 :      * Dynamically observed state about the execution of this opcode. These are
     143                 :      * hints about the script for use during compilation.
     144                 :      */
     145                 :     bool arrayWriteHole: 1;  /* SETELEM which has written to an array hole. */
     146                 :     bool getStringElement:1; /* GETELEM which has accessed string properties. */
     147                 :     bool accessGetter: 1;    /* Property read on a shape with a getter hook. */
     148                 : 
     149                 :     /* Stack depth before this opcode. */
     150                 :     uint32_t stackDepth;
     151                 : 
     152                 :   private:
     153                 : 
     154                 :     union {
     155                 :         /* If this is a JOF_TYPESET opcode, index into the observed types for the op. */
     156                 :         types::TypeSet *observedTypes;
     157                 : 
     158                 :         /* If this is a loop head (TRACE or NOTRACE), information about the loop. */
     159                 :         LoopAnalysis *loop;
     160                 :     };
     161                 : 
     162                 :     /* --------- Lifetime analysis --------- */
     163                 : 
     164                 :     /* Any allocation computed downstream for this bytecode. */
     165                 :     mjit::RegisterAllocation *allocation;
     166                 : 
     167                 :     /* --------- SSA analysis --------- */
     168                 : 
     169                 :     /* Generated location of each value popped by this bytecode. */
     170                 :     SSAValue *poppedValues;
     171                 : 
     172                 :     /* Points where values pushed or written by this bytecode are popped. */
     173                 :     SSAUseChain **pushedUses;
     174                 : 
     175                 :     union {
     176                 :         /*
     177                 :          * If this is a join point (implies jumpTarget), any slots at this
     178                 :          * point which can have a different values than at the immediate
     179                 :          * predecessor in the bytecode. Array is terminated by an entry with
     180                 :          * a zero slot.
     181                 :          */
     182                 :         SlotValue *newValues;
     183                 : 
     184                 :         /*
     185                 :          * Vector used during SSA analysis to store values in need of merging
     186                 :          * at this point. If this has incoming forward jumps and we have not
     187                 :          * yet reached this point, stores values for entries on the stack and
     188                 :          * for variables which have changed since the branch. If this is a loop
     189                 :          * head and we haven't reached the back edge yet, stores loop phi nodes
     190                 :          * for variables and entries live at the head of the loop.
     191                 :          */
     192                 :         Vector<SlotValue> *pendingValues;
     193                 :     };
     194                 : 
     195                 :     /* --------- Type inference --------- */
     196                 : 
     197                 :     /* Types for all values pushed by this bytecode. */
     198                 :     types::TypeSet *pushedTypes;
     199                 : 
     200                 :     /* Any type barriers in place at this bytecode. */
     201                 :     types::TypeBarrier *typeBarriers;
     202                 : };
     203                 : 
     204                 : static inline unsigned
     205        41761257 : GetDefCount(JSScript *script, unsigned offset)
     206                 : {
     207        41761257 :     JS_ASSERT(offset < script->length);
     208        41761257 :     jsbytecode *pc = script->code + offset;
     209                 : 
     210                 :     /*
     211                 :      * Add an extra pushed value for OR/AND opcodes, so that they are included
     212                 :      * in the pushed array of stack values for type inference.
     213                 :      */
     214        41761257 :     switch (JSOp(*pc)) {
     215                 :       case JSOP_OR:
     216                 :       case JSOP_AND:
     217           23346 :         return 1;
     218                 :       case JSOP_FILTER:
     219             136 :         return 2;
     220                 :       case JSOP_PICK:
     221                 :         /*
     222                 :          * Pick pops and pushes how deep it looks in the stack + 1
     223                 :          * items. i.e. if the stack were |a b[2] c[1] d[0]|, pick 2
     224                 :          * would pop b, c, and d to rearrange the stack to |a c[0]
     225                 :          * d[1] b[2]|.
     226                 :          */
     227           65509 :         return (pc[1] + 1);
     228                 :       default:
     229        41672266 :         return StackDefs(script, pc);
     230                 :     }
     231                 : }
     232                 : 
     233                 : static inline unsigned
     234        16050989 : GetUseCount(JSScript *script, unsigned offset)
     235                 : {
     236        16050989 :     JS_ASSERT(offset < script->length);
     237        16050989 :     jsbytecode *pc = script->code + offset;
     238                 : 
     239        16050989 :     if (JSOp(*pc) == JSOP_PICK)
     240           29648 :         return (pc[1] + 1);
     241        16021341 :     if (js_CodeSpec[*pc].nuses == -1)
     242          958118 :         return StackUses(script, pc);
     243        15063223 :     return js_CodeSpec[*pc].nuses;
     244                 : }
     245                 : 
     246                 : /*
     247                 :  * For opcodes which assign to a local variable or argument, track an extra def
     248                 :  * during SSA analysis for the value's use chain and assigned type.
     249                 :  */
     250                 : static inline bool
     251        24111911 : ExtendedDef(jsbytecode *pc)
     252                 : {
     253        24111911 :     switch ((JSOp)*pc) {
     254                 :       case JSOP_SETARG:
     255                 :       case JSOP_INCARG:
     256                 :       case JSOP_DECARG:
     257                 :       case JSOP_ARGINC:
     258                 :       case JSOP_ARGDEC:
     259                 :       case JSOP_SETLOCAL:
     260                 :       case JSOP_INCLOCAL:
     261                 :       case JSOP_DECLOCAL:
     262                 :       case JSOP_LOCALINC:
     263                 :       case JSOP_LOCALDEC:
     264         1201037 :         return true;
     265                 :       default:
     266        22910874 :         return false;
     267                 :     }
     268                 : }
     269                 : 
     270                 : /* Return whether op bytecodes do not fallthrough (they may do a jump). */
     271                 : static inline bool
     272         9173327 : BytecodeNoFallThrough(JSOp op)
     273                 : {
     274         9173327 :     switch (op) {
     275                 :       case JSOP_GOTO:
     276                 :       case JSOP_DEFAULT:
     277                 :       case JSOP_RETURN:
     278                 :       case JSOP_STOP:
     279                 :       case JSOP_RETRVAL:
     280                 :       case JSOP_THROW:
     281                 :       case JSOP_TABLESWITCH:
     282                 :       case JSOP_LOOKUPSWITCH:
     283                 :       case JSOP_FILTER:
     284          362949 :         return true;
     285                 :       case JSOP_GOSUB:
     286                 :         /* These fall through indirectly, after executing a 'finally'. */
     287             937 :         return false;
     288                 :       default:
     289         8809441 :         return false;
     290                 :     }
     291                 : }
     292                 : 
     293                 : /*
     294                 :  * For opcodes which access local variables or arguments, we track an extra
     295                 :  * use during SSA analysis for the value of the variable before/after the op.
     296                 :  */
     297                 : static inline bool
     298         4736006 : ExtendedUse(jsbytecode *pc)
     299                 : {
     300         4736006 :     if (ExtendedDef(pc))
     301          261647 :         return true;
     302         4474359 :     switch ((JSOp)*pc) {
     303                 :       case JSOP_GETARG:
     304                 :       case JSOP_CALLARG:
     305                 :       case JSOP_GETLOCAL:
     306                 :       case JSOP_CALLLOCAL:
     307          160142 :         return true;
     308                 :       default:
     309         4314217 :         return false;
     310                 :     }
     311                 : }
     312                 : 
     313                 : static inline JSOp
     314             136 : ReverseCompareOp(JSOp op)
     315                 : {
     316             136 :     switch (op) {
     317                 :       case JSOP_GT:
     318              68 :         return JSOP_LT;
     319                 :       case JSOP_GE:
     320              32 :         return JSOP_LE;
     321                 :       case JSOP_LT:
     322              24 :         return JSOP_GT;
     323                 :       case JSOP_LE:
     324              12 :         return JSOP_GE;
     325                 :       default:
     326               0 :         JS_NOT_REACHED("unrecognized op");
     327                 :         return op;
     328                 :     }
     329                 : }
     330                 : 
     331                 : static inline unsigned
     332          278430 : FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
     333                 : {
     334                 :     /*
     335                 :      * Get the target offset of a branch. For GOTO opcodes implementing
     336                 :      * 'continue' statements, short circuit any artificial backwards jump
     337                 :      * inserted by the emitter.
     338                 :      */
     339          278430 :     jsbytecode *pc = script->code + offset;
     340          278430 :     unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
     341          278430 :     if (targetOffset < offset) {
     342           22718 :         jsbytecode *target = script->code + targetOffset;
     343           22718 :         JSOp nop = JSOp(*target);
     344           22718 :         if (nop == JSOP_GOTO)
     345              87 :             return targetOffset + GET_JUMP_OFFSET(target);
     346                 :     }
     347          278343 :     return targetOffset;
     348                 : }
     349                 : 
     350                 : /* Common representation of slots throughout analyses and the compiler. */
     351          235507 : static inline uint32_t CalleeSlot() {
     352          235507 :     return 0;
     353                 : }
     354        29467035 : static inline uint32_t ThisSlot() {
     355        29467035 :     return 1;
     356                 : }
     357        45887032 : static inline uint32_t ArgSlot(uint32_t arg) {
     358        45887032 :     return 2 + arg;
     359                 : }
     360         4848574 : static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
     361         4848574 :     return 2 + (script->function() ? script->function()->nargs : 0) + local;
     362                 : }
     363         2246841 : static inline uint32_t TotalSlots(JSScript *script) {
     364         2246841 :     return LocalSlot(script, 0) + script->nfixed;
     365                 : }
     366                 : 
     367           51530 : static inline uint32_t StackSlot(JSScript *script, uint32_t index) {
     368           51530 :     return TotalSlots(script) + index;
     369                 : }
     370                 : 
     371         1497247 : static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc)
     372                 : {
     373         1497247 :     switch (JSOp(*pc)) {
     374                 : 
     375                 :       case JSOP_GETARG:
     376                 :       case JSOP_CALLARG:
     377                 :       case JSOP_SETARG:
     378                 :       case JSOP_INCARG:
     379                 :       case JSOP_DECARG:
     380                 :       case JSOP_ARGINC:
     381                 :       case JSOP_ARGDEC:
     382          178748 :         return ArgSlot(GET_SLOTNO(pc));
     383                 : 
     384                 :       case JSOP_GETLOCAL:
     385                 :       case JSOP_CALLLOCAL:
     386                 :       case JSOP_SETLOCAL:
     387                 :       case JSOP_INCLOCAL:
     388                 :       case JSOP_DECLOCAL:
     389                 :       case JSOP_LOCALINC:
     390                 :       case JSOP_LOCALDEC:
     391         1296797 :         return LocalSlot(script, GET_SLOTNO(pc));
     392                 : 
     393                 :       case JSOP_THIS:
     394           21702 :         return ThisSlot();
     395                 : 
     396                 :       default:
     397               0 :         JS_NOT_REACHED("Bad slot opcode");
     398                 :         return 0;
     399                 :     }
     400                 : }
     401                 : 
     402                 : /* Slot opcodes which update SSA information. */
     403                 : static inline bool
     404         4081349 : BytecodeUpdatesSlot(JSOp op)
     405                 : {
     406         4081349 :     switch (op) {
     407                 :       case JSOP_SETARG:
     408                 :       case JSOP_SETLOCAL:
     409                 :       case JSOP_INCARG:
     410                 :       case JSOP_DECARG:
     411                 :       case JSOP_ARGINC:
     412                 :       case JSOP_ARGDEC:
     413                 :       case JSOP_INCLOCAL:
     414                 :       case JSOP_DECLOCAL:
     415                 :       case JSOP_LOCALINC:
     416                 :       case JSOP_LOCALDEC:
     417          314764 :         return true;
     418                 :       default:
     419         3766585 :         return false;
     420                 :     }
     421                 : }
     422                 : 
     423                 : static inline int32_t
     424           15620 : GetBytecodeInteger(jsbytecode *pc)
     425                 : {
     426           15620 :     switch (JSOp(*pc)) {
     427             693 :       case JSOP_ZERO:   return 0;
     428             248 :       case JSOP_ONE:    return 1;
     429            2945 :       case JSOP_UINT16: return GET_UINT16(pc);
     430              24 :       case JSOP_UINT24: return GET_UINT24(pc);
     431           11700 :       case JSOP_INT8:   return GET_INT8(pc);
     432              10 :       case JSOP_INT32:  return GET_INT32(pc);
     433                 :       default:
     434               0 :         JS_NOT_REACHED("Bad op");
     435                 :         return 0;
     436                 :     }
     437                 : }
     438                 : 
     439                 : /*
     440                 :  * Information about the lifetime of a local or argument. These form a linked
     441                 :  * list describing successive intervals in the program where the variable's
     442                 :  * value may be live. At points in the script not in one of these segments
     443                 :  * (points in a 'lifetime hole'), the variable is dead and registers containing
     444                 :  * its type/payload can be discarded without needing to be synced.
     445                 :  */
     446                 : struct Lifetime
     447                 : {
     448                 :     /*
     449                 :      * Start and end offsets of this lifetime. The variable is live at the
     450                 :      * beginning of every bytecode in this (inclusive) range.
     451                 :      */
     452                 :     uint32_t start;
     453                 :     uint32_t end;
     454                 : 
     455                 :     /*
     456                 :      * In a loop body, endpoint to extend this lifetime with if the variable is
     457                 :      * live in the next iteration.
     458                 :      */
     459                 :     uint32_t savedEnd;
     460                 : 
     461                 :     /*
     462                 :      * This is an artificial segment extending the lifetime of this variable
     463                 :      * when it is live at the head of the loop. It will not be used until the
     464                 :      * next iteration.
     465                 :      */
     466                 :     bool loopTail;
     467                 : 
     468                 :     /*
     469                 :      * The start of this lifetime is a bytecode writing the variable. Each
     470                 :      * write to a variable is associated with a lifetime.
     471                 :      */
     472                 :     bool write;
     473                 : 
     474                 :     /* Next lifetime. The variable is dead from this->end to next->start. */
     475                 :     Lifetime *next;
     476                 : 
     477           62271 :     Lifetime(uint32_t offset, uint32_t savedEnd, Lifetime *next)
     478                 :         : start(offset), end(offset), savedEnd(savedEnd),
     479           62271 :           loopTail(false), write(false), next(next)
     480           62271 :     {}
     481                 : };
     482                 : 
     483                 : /* Basic information for a loop. */
     484                 : class LoopAnalysis
     485                 : {
     486                 :   public:
     487                 :     /* Any loop this one is nested in. */
     488                 :     LoopAnalysis *parent;
     489                 : 
     490                 :     /* Offset of the head of the loop. */
     491                 :     uint32_t head;
     492                 : 
     493                 :     /*
     494                 :      * Offset of the unique jump going to the head of the loop. The code
     495                 :      * between the head and the backedge forms the loop body.
     496                 :      */
     497                 :     uint32_t backedge;
     498                 : 
     499                 :     /* Target offset of the initial jump or fallthrough into the loop. */
     500                 :     uint32_t entry;
     501                 : 
     502                 :     /*
     503                 :      * Start of the last basic block in the loop, excluding the initial jump to
     504                 :      * entry. All code between lastBlock and the backedge runs in every
     505                 :      * iteration, and if entry >= lastBlock all code between entry and the
     506                 :      * backedge runs when the loop is initially entered.
     507                 :      */
     508                 :     uint32_t lastBlock;
     509                 : 
     510                 :     /*
     511                 :      * This loop contains safe points in its body which the interpreter might
     512                 :      * join at directly.
     513                 :      */
     514                 :     bool hasSafePoints;
     515                 : 
     516                 :     /* This loop has calls or inner loops. */
     517                 :     bool hasCallsLoops;
     518                 : };
     519                 : 
     520                 : /* Current lifetime information for a variable. */
     521                 : struct LifetimeVariable
     522                 : {
     523                 :     /* If the variable is currently live, the lifetime segment. */
     524                 :     Lifetime *lifetime;
     525                 : 
     526                 :     /* If the variable is currently dead, the next live segment. */
     527                 :     Lifetime *saved;
     528                 : 
     529                 :     /* Jump preceding the basic block which killed this variable. */
     530                 :     uint32_t savedEnd : 31;
     531                 : 
     532                 :     /* If the variable needs to be kept alive until lifetime->start. */
     533                 :     bool ensured : 1;
     534                 : 
     535                 :     /* Whether this variable is live at offset. */
     536          205883 :     Lifetime * live(uint32_t offset) const {
     537          205883 :         if (lifetime && lifetime->end >= offset)
     538           18692 :             return lifetime;
     539          187191 :         Lifetime *segment = lifetime ? lifetime : saved;
     540          995420 :         while (segment && segment->start <= offset) {
     541          724197 :             if (segment->end >= offset)
     542          103159 :                 return segment;
     543          621038 :             segment = segment->next;
     544                 :         }
     545           84032 :         return NULL;
     546                 :     }
     547                 : 
     548                 :     /*
     549                 :      * Get the offset of the first write to the variable in an inclusive range,
     550                 :      * UINT32_MAX if the variable is not written in the range.
     551                 :      */
     552           33843 :     uint32_t firstWrite(uint32_t start, uint32_t end) const {
     553           33843 :         Lifetime *segment = lifetime ? lifetime : saved;
     554          216304 :         while (segment && segment->start <= end) {
     555          155472 :             if (segment->start >= start && segment->write)
     556            6854 :                 return segment->start;
     557          148618 :             segment = segment->next;
     558                 :         }
     559           26989 :         return UINT32_MAX;
     560                 :     }
     561           23874 :     uint32_t firstWrite(LoopAnalysis *loop) const {
     562           23874 :         return firstWrite(loop->head, loop->backedge);
     563                 :     }
     564                 : 
     565                 :     /* Return true if the variable cannot decrease during the body of a loop. */
     566             734 :     bool nonDecreasing(JSScript *script, LoopAnalysis *loop) const {
     567             734 :         Lifetime *segment = lifetime ? lifetime : saved;
     568            4830 :         while (segment && segment->start <= loop->backedge) {
     569            3420 :             if (segment->start >= loop->head && segment->write) {
     570             734 :                 switch (JSOp(script->code[segment->start])) {
     571                 :                   case JSOP_INCLOCAL:
     572                 :                   case JSOP_LOCALINC:
     573                 :                   case JSOP_INCARG:
     574                 :                   case JSOP_ARGINC:
     575                 :                     break;
     576                 :                   default:
     577              58 :                     return false;
     578                 :                 }
     579                 :             }
     580            3362 :             segment = segment->next;
     581                 :         }
     582             676 :         return true;
     583                 :     }
     584                 : 
     585                 :     /*
     586                 :      * If the variable is only written once in the body of a loop, offset of
     587                 :      * that write. UINT32_MAX otherwise.
     588                 :      */
     589           56243 :     uint32_t onlyWrite(LoopAnalysis *loop) const {
     590           56243 :         uint32_t offset = UINT32_MAX;
     591           56243 :         Lifetime *segment = lifetime ? lifetime : saved;
     592          301129 :         while (segment && segment->start <= loop->backedge) {
     593          190196 :             if (segment->start >= loop->head && segment->write) {
     594           20258 :                 if (offset != UINT32_MAX)
     595            1553 :                     return UINT32_MAX;
     596           18705 :                 offset = segment->start;
     597                 :             }
     598          188643 :             segment = segment->next;
     599                 :         }
     600           54690 :         return offset;
     601                 :     }
     602                 : 
     603                 : #ifdef DEBUG
     604                 :     void print() const;
     605                 : #endif
     606                 : };
     607                 : 
     608                 : struct SSAPhiNode;
     609                 : 
     610                 : /*
     611                 :  * Representation of values on stack or in slots at each point in the script.
     612                 :  * Values are independent from the bytecode position, and mean the same thing
     613                 :  * everywhere in the script. SSA values are immutable, except for contents of
     614                 :  * the values and types in an SSAPhiNode.
     615                 :  */
     616                 : class SSAValue
     617                 : {
     618                 :     friend class ScriptAnalysis;
     619                 : 
     620                 :   public:
     621                 :     enum Kind {
     622                 :         EMPTY  = 0, /* Invalid entry. */
     623                 :         PUSHED = 1, /* Value pushed by some bytecode. */
     624                 :         VAR    = 2, /* Initial or written value to some argument or local. */
     625                 :         PHI    = 3  /* Selector for one of several values. */
     626                 :     };
     627                 : 
     628        30737258 :     Kind kind() const {
     629        30737258 :         JS_ASSERT(u.pushed.kind == u.var.kind && u.pushed.kind == u.phi.kind);
     630                 : 
     631                 :         /* Use a bitmask because MSVC wants to use -1 for PHI nodes. */
     632        30737258 :         return (Kind) (u.pushed.kind & 0x3);
     633                 :     }
     634                 : 
     635           52245 :     bool operator==(const SSAValue &o) const {
     636           52245 :         return !memcmp(this, &o, sizeof(SSAValue));
     637                 :     }
     638                 : 
     639                 :     /* Accessors for values pushed by a bytecode within this script. */
     640                 : 
     641         4185594 :     uint32_t pushedOffset() const {
     642         4185594 :         JS_ASSERT(kind() == PUSHED);
     643         4185594 :         return u.pushed.offset;
     644                 :     }
     645                 : 
     646         4065330 :     uint32_t pushedIndex() const {
     647         4065330 :         JS_ASSERT(kind() == PUSHED);
     648         4065330 :         return u.pushed.index;
     649                 :     }
     650                 : 
     651                 :     /* Accessors for initial and written values of arguments and (undefined) locals. */
     652                 : 
     653          471969 :     bool varInitial() const {
     654          471969 :         JS_ASSERT(kind() == VAR);
     655          471969 :         return u.var.initial;
     656                 :     }
     657                 : 
     658          331493 :     uint32_t varSlot() const {
     659          331493 :         JS_ASSERT(kind() == VAR);
     660          331493 :         return u.var.slot;
     661                 :     }
     662                 : 
     663          186132 :     uint32_t varOffset() const {
     664          186132 :         JS_ASSERT(!varInitial());
     665          186132 :         return u.var.offset;
     666                 :     }
     667                 : 
     668                 :     /* Accessors for phi nodes. */
     669                 : 
     670                 :     uint32_t phiSlot() const;
     671                 :     uint32_t phiLength() const;
     672                 :     const SSAValue &phiValue(uint32_t i) const;
     673                 :     types::TypeSet *phiTypes() const;
     674                 : 
     675                 :     /* Offset at which this phi node was created. */
     676          153534 :     uint32_t phiOffset() const {
     677          153534 :         JS_ASSERT(kind() == PHI);
     678          153534 :         return u.phi.offset;
     679                 :     }
     680                 : 
     681          319234 :     SSAPhiNode *phiNode() const {
     682          319234 :         JS_ASSERT(kind() == PHI);
     683          319234 :         return u.phi.node;
     684                 :     }
     685                 : 
     686                 :     /* Other accessors. */
     687                 : 
     688                 : #ifdef DEBUG
     689                 :     void print() const;
     690                 : #endif
     691                 : 
     692         4223949 :     void clear() {
     693         4223949 :         PodZero(this);
     694         4223949 :         JS_ASSERT(kind() == EMPTY);
     695         4223949 :     }
     696                 : 
     697         2211128 :     void initPushed(uint32_t offset, uint32_t index) {
     698         2211128 :         clear();
     699         2211128 :         u.pushed.kind = PUSHED;
     700         2211128 :         u.pushed.offset = offset;
     701         2211128 :         u.pushed.index = index;
     702         2211128 :     }
     703                 : 
     704          427804 :     static SSAValue PushedValue(uint32_t offset, uint32_t index) {
     705                 :         SSAValue v;
     706          427804 :         v.initPushed(offset, index);
     707                 :         return v;
     708                 :     }
     709                 : 
     710           12959 :     void initInitial(uint32_t slot) {
     711           12959 :         clear();
     712           12959 :         u.var.kind = VAR;
     713           12959 :         u.var.initial = true;
     714           12959 :         u.var.slot = slot;
     715           12959 :     }
     716                 : 
     717           43130 :     void initWritten(uint32_t slot, uint32_t offset) {
     718           43130 :         clear();
     719           43130 :         u.var.kind = VAR;
     720           43130 :         u.var.initial = false;
     721           43130 :         u.var.slot = slot;
     722           43130 :         u.var.offset = offset;
     723           43130 :     }
     724                 : 
     725             174 :     static SSAValue WrittenVar(uint32_t slot, uint32_t offset) {
     726                 :         SSAValue v;
     727             174 :         v.initWritten(slot, offset);
     728                 :         return v;
     729                 :     }
     730                 : 
     731           15290 :     void initPhi(uint32_t offset, SSAPhiNode *node) {
     732           15290 :         clear();
     733           15290 :         u.phi.kind = PHI;
     734           15290 :         u.phi.offset = offset;
     735           15290 :         u.phi.node = node;
     736           15290 :     }
     737                 : 
     738             111 :     static SSAValue PhiValue(uint32_t offset, SSAPhiNode *node) {
     739                 :         SSAValue v;
     740             111 :         v.initPhi(offset, node);
     741                 :         return v;
     742                 :     }
     743                 : 
     744                 :   private:
     745                 :     union {
     746                 :         struct {
     747                 :             Kind kind : 2;
     748                 :             uint32_t offset : 30;
     749                 :             uint32_t index;
     750                 :         } pushed;
     751                 :         struct {
     752                 :             Kind kind : 2;
     753                 :             bool initial : 1;
     754                 :             uint32_t slot : 29;
     755                 :             uint32_t offset;
     756                 :         } var;
     757                 :         struct {
     758                 :             Kind kind : 2;
     759                 :             uint32_t offset : 30;
     760                 :             SSAPhiNode *node;
     761                 :         } phi;
     762                 :     } u;
     763                 : };
     764                 : 
     765                 : /*
     766                 :  * Mutable component of a phi node, with the possible values of the phi
     767                 :  * and the possible types of the node as determined by type inference.
     768                 :  * When phi nodes are copied around, any updates to the original will
     769                 :  * be seen by all copies made.
     770                 :  */
     771                 : struct SSAPhiNode
     772                 : {
     773                 :     types::TypeSet types;
     774                 :     uint32_t slot;
     775                 :     uint32_t length;
     776                 :     SSAValue *options;
     777                 :     SSAUseChain *uses;
     778           15179 :     SSAPhiNode() { PodZero(this); }
     779                 : };
     780                 : 
     781                 : inline uint32_t
     782           18560 : SSAValue::phiSlot() const
     783                 : {
     784           18560 :     return u.phi.node->slot;
     785                 : }
     786                 : 
     787                 : inline uint32_t
     788               0 : SSAValue::phiLength() const
     789                 : {
     790               0 :     JS_ASSERT(kind() == PHI);
     791               0 :     return u.phi.node->length;
     792                 : }
     793                 : 
     794                 : inline const SSAValue &
     795               0 : SSAValue::phiValue(uint32_t i) const
     796                 : {
     797               0 :     JS_ASSERT(kind() == PHI && i < phiLength());
     798               0 :     return u.phi.node->options[i];
     799                 : }
     800                 : 
     801                 : inline types::TypeSet *
     802                 : SSAValue::phiTypes() const
     803                 : {
     804                 :     JS_ASSERT(kind() == PHI);
     805                 :     return &u.phi.node->types;
     806                 : }
     807                 : 
     808                 : class SSAUseChain
     809                 : {
     810                 :   public:
     811                 :     bool popped : 1;
     812                 :     uint32_t offset : 31;
     813                 :     /* FIXME: Assert that only the proper arm of this union is accessed. */
     814                 :     union {
     815                 :         uint32_t which;
     816                 :         SSAPhiNode *phi;
     817                 :     } u;
     818                 :     SSAUseChain *next;
     819                 : 
     820           23019 :     SSAUseChain() { PodZero(this); }
     821                 : };
     822                 : 
     823                 : class SlotValue
     824                 : {
     825                 :   public:
     826                 :     uint32_t slot;
     827                 :     SSAValue value;
     828           63912 :     SlotValue(uint32_t slot, const SSAValue &value) : slot(slot), value(value) {}
     829                 : };
     830                 : 
     831                 : /* Analysis information about a script. */
     832                 : class ScriptAnalysis
     833                 : {
     834                 :     friend class Bytecode;
     835                 : 
     836                 :     JSScript *script;
     837                 : 
     838                 :     Bytecode **codeArray;
     839                 : 
     840                 :     uint32_t numSlots;
     841                 : 
     842                 :     bool outOfMemory;
     843                 :     bool hadFailure;
     844                 : 
     845                 :     bool *escapedSlots;
     846                 : 
     847                 :     /* Which analyses have been performed. */
     848                 :     bool ranBytecode_;
     849                 :     bool ranSSA_;
     850                 :     bool ranLifetimes_;
     851                 :     bool ranInference_;
     852                 : 
     853                 : #ifdef DEBUG
     854                 :     /* Whether the compartment was in debug mode when we performed the analysis. */
     855                 :     bool originalDebugMode_: 1;
     856                 : #endif
     857                 : 
     858                 :     /* --------- Bytecode analysis --------- */
     859                 : 
     860                 :     bool usesReturnValue_:1;
     861                 :     bool usesScopeChain_:1;
     862                 :     bool usesThisValue_:1;
     863                 :     bool hasFunctionCalls_:1;
     864                 :     bool modifiesArguments_:1;
     865                 :     bool extendsScope_:1;
     866                 :     bool addsScopeObjects_:1;
     867                 :     bool localsAliasStack_:1;
     868                 :     bool isInlineable:1;
     869                 :     bool isCompileable:1;
     870                 :     bool canTrackVars:1;
     871                 : 
     872                 :     uint32_t numReturnSites_;
     873                 : 
     874                 :     /* --------- Lifetime analysis --------- */
     875                 : 
     876                 :     LifetimeVariable *lifetimes;
     877                 : 
     878                 :   public:
     879                 : 
     880          166090 :     ScriptAnalysis(JSScript *script) { 
     881          166090 :         PodZero(this);
     882          166090 :         this->script = script;
     883                 : #ifdef DEBUG
     884          166090 :         this->originalDebugMode_ = script->compartment()->debugMode();
     885                 : #endif        
     886          166090 :     }
     887                 : 
     888       102703212 :     bool ranBytecode() { return ranBytecode_; }
     889           78853 :     bool ranSSA() { return ranSSA_; }
     890          451748 :     bool ranLifetimes() { return ranLifetimes_; }
     891       863138813 :     bool ranInference() { return ranInference_; }
     892                 : 
     893                 :     void analyzeBytecode(JSContext *cx);
     894                 :     void analyzeSSA(JSContext *cx);
     895                 :     void analyzeLifetimes(JSContext *cx);
     896                 :     void analyzeTypes(JSContext *cx);
     897                 : 
     898                 :     /* Analyze the effect of invoking 'new' on script. */
     899                 :     void analyzeTypesNew(JSContext *cx);
     900                 : 
     901         4560168 :     bool OOM() { return outOfMemory; }
     902          596223 :     bool failed() { return hadFailure; }
     903            4573 :     bool inlineable(uint32_t argc) { return isInlineable && argc == script->function()->nargs; }
     904          103394 :     bool compileable() { return isCompileable; }
     905                 : 
     906                 :     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
     907          121901 :     bool usesReturnValue() const { return usesReturnValue_; }
     908                 : 
     909                 :     /* Whether there are NAME bytecodes which can access the frame's scope chain. */
     910           43919 :     bool usesScopeChain() const { return usesScopeChain_; }
     911                 : 
     912            2971 :     bool usesThisValue() const { return usesThisValue_; }
     913           24523 :     bool hasFunctionCalls() const { return hasFunctionCalls_; }
     914            2997 :     uint32_t numReturnSites() const { return numReturnSites_; }
     915                 : 
     916                 :     /*
     917                 :      * True if all named formal arguments are not modified. If the arguments
     918                 :      * object cannot escape, the arguments are never modified within the script.
     919                 :      */
     920             400 :     bool modifiesArguments() { return modifiesArguments_; }
     921                 : 
     922                 :     /*
     923                 :      * True if the script may extend declarations in its top level scope with
     924                 :      * dynamic fun/var declarations or through eval.
     925                 :      */
     926            1431 :     bool extendsScope() { return extendsScope_; }
     927                 : 
     928                 :     /* True if the script may add block or with objects to its scope chain. */
     929           80784 :     bool addsScopeObjects() { return addsScopeObjects_; }
     930                 : 
     931                 :     /*
     932                 :      * True if there are any LOCAL opcodes aliasing values on the stack (above
     933                 :      * script->nfixed).
     934                 :      */
     935           26595 :     bool localsAliasStack() { return localsAliasStack_; }
     936                 : 
     937                 :     /* Accessors for bytecode information. */
     938                 : 
     939       106028900 :     Bytecode& getCode(uint32_t offset) {
     940       106028900 :         JS_ASSERT(offset < script->length);
     941       106028900 :         JS_ASSERT(codeArray[offset]);
     942       106028900 :         return *codeArray[offset];
     943                 :     }
     944        80790330 :     Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
     945                 : 
     946        78264448 :     Bytecode* maybeCode(uint32_t offset) {
     947        78264448 :         JS_ASSERT(offset < script->length);
     948        78264448 :         return codeArray[offset];
     949                 :     }
     950        10557055 :     Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
     951                 : 
     952          643913 :     bool jumpTarget(uint32_t offset) {
     953          643913 :         JS_ASSERT(offset < script->length);
     954          643913 :         return codeArray[offset] && codeArray[offset]->jumpTarget;
     955                 :     }
     956          643913 :     bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script->code); }
     957                 : 
     958           51270 :     bool popGuaranteed(jsbytecode *pc) {
     959           51270 :         jsbytecode *next = pc + GetBytecodeLength(pc);
     960           51270 :         return JSOp(*next) == JSOP_POP && !jumpTarget(next);
     961                 :     }
     962                 : 
     963           29841 :     bool incrementInitialValueObserved(jsbytecode *pc) {
     964           29841 :         const JSCodeSpec *cs = &js_CodeSpec[*pc];
     965           29841 :         return (cs->format & JOF_POST) && !popGuaranteed(pc);
     966                 :     }
     967                 : 
     968        76883322 :     types::TypeSet *bytecodeTypes(const jsbytecode *pc) {
     969        76883322 :         JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
     970        76883322 :         return getCode(pc).observedTypes;
     971                 :     }
     972                 : 
     973         2592532 :     const SSAValue &poppedValue(uint32_t offset, uint32_t which) {
     974         2592532 :         JS_ASSERT(offset < script->length);
     975         2592532 :         JS_ASSERT(which < GetUseCount(script, offset) +
     976         2592532 :                   (ExtendedUse(script->code + offset) ? 1 : 0));
     977         2592532 :         return getCode(offset).poppedValues[which];
     978                 :     }
     979         2559236 :     const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which) {
     980         2559236 :         return poppedValue(pc - script->code, which);
     981                 :     }
     982                 : 
     983          470063 :     const SlotValue *newValues(uint32_t offset) {
     984          470063 :         JS_ASSERT(offset < script->length);
     985          470063 :         return getCode(offset).newValues;
     986                 :     }
     987          470063 :     const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script->code); }
     988                 : 
     989        15109299 :     types::TypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
     990        15109299 :         JS_ASSERT(offset < script->length);
     991        15109299 :         JS_ASSERT(which < GetDefCount(script, offset) +
     992        15109299 :                   (ExtendedDef(script->code + offset) ? 1 : 0));
     993        15109299 :         types::TypeSet *array = getCode(offset).pushedTypes;
     994        15109299 :         JS_ASSERT(array);
     995        15109299 :         return array + which;
     996                 :     }
     997        10966093 :     types::TypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
     998        10966093 :         return pushedTypes(pc - script->code, which);
     999                 :     }
    1000                 : 
    1001                 :     bool hasPushedTypes(const jsbytecode *pc) { return getCode(pc).pushedTypes != NULL; }
    1002                 : 
    1003          518031 :     types::TypeBarrier *typeBarriers(JSContext *cx, uint32_t offset) {
    1004          518031 :         if (getCode(offset).typeBarriers)
    1005          297994 :             pruneTypeBarriers(cx, offset);
    1006          518031 :         return getCode(offset).typeBarriers;
    1007                 :     }
    1008          518031 :     types::TypeBarrier *typeBarriers(JSContext *cx, const jsbytecode *pc) {
    1009          518031 :         return typeBarriers(cx, pc - script->code);
    1010                 :     }
    1011                 :     void addTypeBarrier(JSContext *cx, const jsbytecode *pc,
    1012                 :                         types::TypeSet *target, types::Type type);
    1013                 :     void addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc,
    1014                 :                                  types::TypeSet *target, JSObject *singleton, jsid singletonId);
    1015                 : 
    1016                 :     /* Remove obsolete type barriers at the given offset. */
    1017                 :     void pruneTypeBarriers(JSContext *cx, uint32_t offset);
    1018                 : 
    1019                 :     /*
    1020                 :      * Remove still-active type barriers at the given offset. If 'all' is set,
    1021                 :      * then all barriers are removed, otherwise only those deemed excessive
    1022                 :      * are removed.
    1023                 :      */
    1024                 :     void breakTypeBarriers(JSContext *cx, uint32_t offset, bool all);
    1025                 : 
    1026                 :     /* Break all type barriers used in computing v. */
    1027                 :     void breakTypeBarriersSSA(JSContext *cx, const SSAValue &v);
    1028                 : 
    1029                 :     inline void addPushedType(JSContext *cx, uint32_t offset, uint32_t which, types::Type type);
    1030                 : 
    1031         2588735 :     types::TypeSet *getValueTypes(const SSAValue &v) {
    1032         2588735 :         switch (v.kind()) {
    1033                 :           case SSAValue::PUSHED:
    1034         2268466 :             return pushedTypes(v.pushedOffset(), v.pushedIndex());
    1035                 :           case SSAValue::VAR:
    1036          108650 :             JS_ASSERT(!slotEscapes(v.varSlot()));
    1037          108650 :             if (v.varInitial()) {
    1038           54265 :                 return types::TypeScript::SlotTypes(script, v.varSlot());
    1039                 :             } else {
    1040                 :                 /*
    1041                 :                  * Results of intermediate assignments have the same type as
    1042                 :                  * the first type pushed by the assignment op. Note that this
    1043                 :                  * may not be the exact same value as was pushed, due to
    1044                 :                  * post-inc/dec ops.
    1045                 :                  */
    1046           54385 :                 return pushedTypes(v.varOffset(), 0);
    1047                 :             }
    1048                 :           case SSAValue::PHI:
    1049          211619 :             return &v.phiNode()->types;
    1050                 :           default:
    1051                 :             /* Cannot compute types for empty SSA values. */
    1052               0 :             JS_NOT_REACHED("Bad SSA value");
    1053                 :             return NULL;
    1054                 :         }
    1055                 :     }
    1056                 : 
    1057               4 :     types::TypeSet *poppedTypes(uint32_t offset, uint32_t which) {
    1058               4 :         return getValueTypes(poppedValue(offset, which));
    1059                 :     }
    1060         2395381 :     types::TypeSet *poppedTypes(const jsbytecode *pc, uint32_t which) {
    1061         2395381 :         return getValueTypes(poppedValue(pc, which));
    1062                 :     }
    1063                 : 
    1064                 :     /* Whether an arithmetic operation is operating on integers, with an integer result. */
    1065                 :     bool integerOperation(JSContext *cx, jsbytecode *pc);
    1066                 : 
    1067         3950606 :     bool trackUseChain(const SSAValue &v) {
    1068         3950606 :         JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
    1069         3950606 :         return v.kind() != SSAValue::EMPTY &&
    1070         3950606 :             (v.kind() != SSAValue::VAR || !v.varInitial());
    1071                 :     }
    1072                 : 
    1073                 :     /*
    1074                 :      * Get the use chain for an SSA value. May be invalid for some opcodes in
    1075                 :      * scripts where localsAliasStack(). You have been warned!
    1076                 :      */
    1077         1913882 :     SSAUseChain *& useChain(const SSAValue &v) {
    1078         1913882 :         JS_ASSERT(trackUseChain(v));
    1079         1913882 :         if (v.kind() == SSAValue::PUSHED)
    1080         1796864 :             return getCode(v.pushedOffset()).pushedUses[v.pushedIndex()];
    1081          117018 :         if (v.kind() == SSAValue::VAR)
    1082           63130 :             return getCode(v.varOffset()).pushedUses[GetDefCount(script, v.varOffset())];
    1083           53888 :         return v.phiNode()->uses;
    1084                 :     }
    1085                 : 
    1086          928895 :     mjit::RegisterAllocation *&getAllocation(uint32_t offset) {
    1087          928895 :         JS_ASSERT(offset < script->length);
    1088          928895 :         return getCode(offset).allocation;
    1089                 :     }
    1090          928253 :     mjit::RegisterAllocation *&getAllocation(const jsbytecode *pc) {
    1091          928253 :         return getAllocation(pc - script->code);
    1092                 :     }
    1093                 : 
    1094          246979 :     LoopAnalysis *getLoop(uint32_t offset) {
    1095          246979 :         JS_ASSERT(offset < script->length);
    1096          246979 :         return getCode(offset).loop;
    1097                 :     }
    1098          246436 :     LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script->code); }
    1099                 : 
    1100                 :     /* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */
    1101           47667 :     jsbytecode *getCallPC(jsbytecode *pc)
    1102                 :     {
    1103           47667 :         SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script->code, 0));
    1104           47667 :         JS_ASSERT(uses && uses->popped);
    1105           47667 :         JS_ASSERT(js_CodeSpec[script->code[uses->offset]].format & JOF_INVOKE);
    1106           47667 :         return script->code + uses->offset;
    1107                 :     }
    1108                 : 
    1109                 :     /* Accessors for local variable information. */
    1110                 : 
    1111                 :     /*
    1112                 :      * Escaping slots include all slots that can be accessed in ways other than
    1113                 :      * through the corresponding LOCAL/ARG opcode. This includes all closed
    1114                 :      * slots in the script, all slots in scripts which use eval or are in debug
    1115                 :      * mode, and slots which are aliased by NAME or similar opcodes in the
    1116                 :      * containing script (which does not imply the variable is closed).
    1117                 :      */
    1118         2969271 :     bool slotEscapes(uint32_t slot) {
    1119         2969271 :         JS_ASSERT(script->compartment()->activeAnalysis);
    1120         2969271 :         if (slot >= numSlots)
    1121          238094 :             return true;
    1122         2731177 :         return escapedSlots[slot];
    1123                 :     }
    1124                 : 
    1125                 :     /*
    1126                 :      * Whether we distinguish different writes of this variable while doing
    1127                 :      * SSA analysis. Escaping locals can be written in other scripts, and the
    1128                 :      * presence of NAME opcodes which could alias local variables or arguments
    1129                 :      * keeps us from tracking variable values at each point.
    1130                 :      */
    1131         1529962 :     bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars; }
    1132                 : 
    1133          290440 :     const LifetimeVariable & liveness(uint32_t slot) {
    1134          290440 :         JS_ASSERT(script->compartment()->activeAnalysis);
    1135          290440 :         JS_ASSERT(!slotEscapes(slot));
    1136          290440 :         return lifetimes[slot];
    1137                 :     }
    1138                 : 
    1139                 :     /*
    1140                 :      * If a NAME or similar opcode is definitely accessing a particular slot
    1141                 :      * of a script this one is nested in, get that script/slot.
    1142                 :      */
    1143                 :     struct NameAccess {
    1144                 :         JSScript *script;
    1145                 :         types::TypeScriptNesting *nesting;
    1146                 :         uint32_t slot;
    1147                 : 
    1148                 :         /* Decompose the slot above. */
    1149                 :         bool arg;
    1150                 :         uint32_t index;
    1151                 : 
    1152           29343 :         const Value **basePointer() const {
    1153           29343 :             return arg ? &nesting->argArray : &nesting->varArray;
    1154                 :         }
    1155                 :     };
    1156                 :     NameAccess resolveNameAccess(JSContext *cx, jsid id, bool addDependency = false);
    1157                 : 
    1158                 :     void printSSA(JSContext *cx);
    1159                 :     void printTypes(JSContext *cx);
    1160                 : 
    1161                 :     void clearAllocations();
    1162                 : 
    1163                 :   private:
    1164               0 :     void setOOM(JSContext *cx) {
    1165               0 :         if (!outOfMemory)
    1166               0 :             js_ReportOutOfMemory(cx);
    1167               0 :         outOfMemory = true;
    1168               0 :         hadFailure = true;
    1169               0 :     }
    1170                 : 
    1171                 :     /* Bytecode helpers */
    1172                 :     inline bool addJump(JSContext *cx, unsigned offset,
    1173                 :                         unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
    1174                 :                         unsigned stackDepth);
    1175                 :     void checkAliasedName(JSContext *cx, jsbytecode *pc);
    1176                 : 
    1177                 :     /* Lifetime helpers */
    1178                 :     inline void addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
    1179                 :                             LifetimeVariable **&saved, unsigned &savedCount);
    1180                 :     inline void killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
    1181                 :                              LifetimeVariable **&saved, unsigned &savedCount);
    1182                 :     inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
    1183                 :     inline void ensureVariable(LifetimeVariable &var, unsigned until);
    1184                 : 
    1185                 :     /* Current value for a variable or stack value, as tracked during SSA. */
    1186                 :     struct SSAValueInfo
    1187                 :     {
    1188                 :         SSAValue v;
    1189                 : 
    1190                 :         /*
    1191                 :          * Sizes of branchTargets the last time this slot was written. Branches less
    1192                 :          * than this threshold do not need to be inspected if the slot is written
    1193                 :          * again, as they will already reflect the slot's value at the branch.
    1194                 :          */
    1195                 :         int32_t branchSize;
    1196                 :     };
    1197                 : 
    1198                 :     /* SSA helpers */
    1199                 :     bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv);
    1200                 :     void insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
    1201                 :     void mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv);
    1202                 :     void checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
    1203                 :                            Vector<SlotValue> *pending);
    1204                 :     void checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
    1205                 :                            SSAValueInfo *values, uint32_t stackDepth);
    1206                 :     void checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
    1207                 :                               Vector<uint32_t> &exceptionTargets);
    1208                 :     void mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
    1209                 :                            const Vector<uint32_t> &branchTargets, uint32_t currentOffset);
    1210                 :     void mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
    1211                 :                               const Vector<uint32_t> &exceptionTargets);
    1212                 :     void mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
    1213                 :                                   const Vector<uint32_t> &exceptionTargets);
    1214                 :     void freezeNewValues(JSContext *cx, uint32_t offset);
    1215                 : 
    1216           38594 :     struct TypeInferenceState {
    1217                 :         Vector<SSAPhiNode *> phiNodes;
    1218                 :         bool hasGetSet;
    1219                 :         bool hasHole;
    1220                 :         types::TypeSet *forTypes;
    1221           38594 :         TypeInferenceState(JSContext *cx)
    1222           38594 :             : phiNodes(cx), hasGetSet(false), hasHole(false), forTypes(NULL)
    1223           38594 :         {}
    1224                 :     };
    1225                 : 
    1226                 :     /* Type inference helpers */
    1227                 :     bool analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state);
    1228                 :     bool followEscapingArguments(JSContext *cx, const SSAValue &v, Vector<SSAValue> *seen);
    1229                 :     bool followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<SSAValue> *seen);
    1230                 : 
    1231                 :   public:
    1232                 : #ifdef DEBUG
    1233                 :     void assertMatchingDebugMode();
    1234                 : #else
    1235                 :     void assertMatchingDebugMode() { }
    1236                 : #endif
    1237                 : };
    1238                 : 
    1239                 : /* Protect analysis structures from GC while they are being used. */
    1240                 : class AutoEnterAnalysis
    1241                 : {
    1242                 :     JSCompartment *compartment;
    1243                 :     bool oldActiveAnalysis;
    1244                 :     bool left;
    1245                 : 
    1246          260776 :     void construct(JSCompartment *compartment)
    1247                 :     {
    1248          260776 :         this->compartment = compartment;
    1249          260776 :         oldActiveAnalysis = compartment->activeAnalysis;
    1250          260776 :         compartment->activeAnalysis = true;
    1251          260776 :         left = false;
    1252          260776 :     }
    1253                 : 
    1254                 :   public:
    1255          213121 :     AutoEnterAnalysis(JSContext *cx) { construct(cx->compartment); }
    1256           47655 :     AutoEnterAnalysis(JSCompartment *compartment) { construct(compartment); }
    1257                 : 
    1258          260794 :     void leave()
    1259                 :     {
    1260          260794 :         if (!left) {
    1261          260776 :             left = true;
    1262          260776 :             compartment->activeAnalysis = oldActiveAnalysis;
    1263                 :         }
    1264          260794 :     }
    1265                 : 
    1266          260776 :     ~AutoEnterAnalysis()
    1267                 :     {
    1268          260776 :         leave();
    1269          260776 :     }
    1270                 : };
    1271                 : 
    1272                 : /* SSA value as used by CrossScriptSSA, identifies the frame it came from. */
    1273                 : struct CrossSSAValue
    1274                 : {
    1275                 :     unsigned frame;
    1276                 :     SSAValue v;
    1277          468893 :     CrossSSAValue(unsigned frame, const SSAValue &v) : frame(frame), v(v) {}
    1278                 : };
    1279                 : 
    1280                 : /*
    1281                 :  * Analysis for managing SSA values from multiple call stack frames. These are
    1282                 :  * created by the backend compiler when inlining functions, and allow for
    1283                 :  * values to be tracked as they flow into or out of the inlined frames.
    1284                 :  */
    1285                 : class CrossScriptSSA
    1286           95862 : {
    1287                 :   public:
    1288                 : 
    1289                 :     static const uint32_t OUTER_FRAME = UINT32_MAX;
    1290                 :     static const unsigned INVALID_FRAME = uint32_t(-2);
    1291                 : 
    1292            6266 :     struct Frame {
    1293                 :         uint32_t index;
    1294                 :         JSScript *script;
    1295                 :         uint32_t depth;  /* Distance from outer frame to this frame, in sizeof(Value) */
    1296                 :         uint32_t parent;
    1297                 :         jsbytecode *parentpc;
    1298                 : 
    1299           98804 :         Frame(uint32_t index, JSScript *script, uint32_t depth, uint32_t parent, jsbytecode *parentpc)
    1300           98804 :             : index(index), script(script), depth(depth), parent(parent), parentpc(parentpc)
    1301           98804 :         {}
    1302                 :     };
    1303                 : 
    1304          355883 :     const Frame &getFrame(uint32_t index) {
    1305          355883 :         if (index == OUTER_FRAME)
    1306          324742 :             return outerFrame;
    1307           31141 :         return inlineFrames[index];
    1308                 :     }
    1309                 : 
    1310          444176 :     unsigned numFrames() { return 1 + inlineFrames.length(); }
    1311          353994 :     const Frame &iterFrame(unsigned i) {
    1312          353994 :         if (i == 0)
    1313          128314 :             return outerFrame;
    1314          225680 :         return inlineFrames[i - 1];
    1315                 :     }
    1316                 : 
    1317           33573 :     JSScript *outerScript() { return outerFrame.script; }
    1318                 : 
    1319                 :     /* Total length of scripts preceding a frame. */
    1320           96663 :     size_t frameLength(uint32_t index) {
    1321           96663 :         if (index == OUTER_FRAME)
    1322           93731 :             return 0;
    1323            2932 :         size_t res = outerFrame.script->length;
    1324           67468 :         for (unsigned i = 0; i < index; i++)
    1325           64536 :             res += inlineFrames[i].script->length;
    1326            2932 :         return res;
    1327                 :     }
    1328                 : 
    1329            4310 :     types::TypeSet *getValueTypes(const CrossSSAValue &cv) {
    1330            4310 :         return getFrame(cv.frame).script->analysis()->getValueTypes(cv.v);
    1331                 :     }
    1332                 : 
    1333            2942 :     bool addInlineFrame(JSScript *script, uint32_t depth, uint32_t parent, jsbytecode *parentpc)
    1334                 :     {
    1335            2942 :         uint32_t index = inlineFrames.length();
    1336            2942 :         return inlineFrames.append(Frame(index, script, depth, parent, parentpc));
    1337                 :     }
    1338                 : 
    1339           95862 :     CrossScriptSSA(JSContext *cx, JSScript *outer)
    1340           95862 :         : cx(cx), outerFrame(OUTER_FRAME, outer, 0, INVALID_FRAME, NULL), inlineFrames(cx)
    1341           95862 :     {}
    1342                 : 
    1343                 :     CrossSSAValue foldValue(const CrossSSAValue &cv);
    1344                 : 
    1345                 :   private:
    1346                 :     JSContext *cx;
    1347                 : 
    1348                 :     Frame outerFrame;
    1349                 :     Vector<Frame> inlineFrames;
    1350                 : };
    1351                 : 
    1352                 : #ifdef DEBUG
    1353                 : void PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc);
    1354                 : #endif
    1355                 : 
    1356                 : static inline bool
    1357            3754 : SpeculateApplyOptimization(jsbytecode *pc)
    1358                 : {
    1359            3754 :     JS_ASSERT(*pc == JSOP_ARGUMENTS);
    1360            3754 :     jsbytecode *nextpc = pc + JSOP_ARGUMENTS_LENGTH;
    1361            3754 :     return *nextpc == JSOP_FUNAPPLY && GET_ARGC(nextpc) == 2;
    1362                 : }
    1363                 : 
    1364                 : } /* namespace analyze */
    1365                 : } /* namespace js */
    1366                 : 
    1367                 : namespace js {
    1368                 : namespace tl {
    1369                 : 
    1370                 : template <> struct IsPodType<js::analyze::LifetimeVariable> { static const bool result = true; };
    1371                 : template <> struct IsPodType<js::analyze::LoopAnalysis>     { static const bool result = true; };
    1372                 : template <> struct IsPodType<js::analyze::SlotValue>        { static const bool result = true; };
    1373                 : template <> struct IsPodType<js::analyze::SSAValue>         { static const bool result = true; };
    1374                 : template <> struct IsPodType<js::analyze::SSAUseChain>      { static const bool result = true; };
    1375                 : 
    1376                 : } /* namespace tl */
    1377                 : } /* namespace js */
    1378                 : 
    1379                 : #endif // jsanalyze_h___

Generated by: LCOV version 1.7