LCOV - app.info - js/src/jsanalyze.h

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