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

Generated by: LCOV version 1.7