LCOV - app.info - js/src/methodjit/LoopState.h

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - LoopState.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 31 | 31 | 100.0 %
| Date: | 2012-04-07 | Functions: | 23 | 23 | 100.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          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                 : #if !defined jsjaeger_loopstate_h__ && defined JS_METHODJIT
          40                 : #define jsjaeger_loopstate_h__
          41                 :
          42                 : #include "jsanalyze.h"
          43                 : #include "methodjit/Compiler.h"
          44                 :
          45                 : namespace js {
          46                 : namespace mjit {
          47                 :
          48                 : /*
          49                 :  * The LoopState keeps track of register and analysis state within the loop
          50                 :  * currently being processed by the Compiler.
          51                 :  *
          52                 :  * There are several analyses we do that are specific to loops: loop carried
          53                 :  * registers, bounds check hoisting, and loop invariant code motion. Brief
          54                 :  * descriptions of these analyses:
          55                 :  *
          56                 :  * Loop carried registers. We allocate registers as we emit code, in a single
          57                 :  * forward pass over the script. Normally this would mean we need to pick the
          58                 :  * register allocation at the head of the loop before any of the body has been
          59                 :  * processed. Instead, while processing the loop body we retroactively mark
          60                 :  * registers as holding the payload of certain entries at the head (being
          61                 :  * carried around the loop), so that the head's allocation ends up holding
          62                 :  * registers that are likely to be used shortly. This can be done provided that
          63                 :  * (a) the register has not been touched since the loop head, (b) the slot
          64                 :  * has not been modified or separately assigned a different register, and (c)
          65                 :  * all prior slow path rejoins in the loop are patched with reloads of the
          66                 :  * register. The register allocation at the loop head must have all entries
          67                 :  * synced, so that prior slow path syncs do not also need patching.
          68                 :  *
          69                 :  * Bounds check hoisting. If we can determine a loop invariant test which
          70                 :  * implies the bounds check at one or more array accesses, we hoist that and
          71                 :  * check it when initially entering the loop (from JIT code or the
          72                 :  * interpreter) and after every stub or C++ call.
          73                 :  *
          74                 :  * Loop invariant code motion. If we can determine a computation (arithmetic,
          75                 :  * array slot pointer or property access) is loop invariant, we give it a slot
          76                 :  * on the stack and preserve its value throughout the loop. We can allocate
          77                 :  * and carry registers for loop invariant slots as for normal slots. These
          78                 :  * slots sit above the frame's normal slots, and are transient --- they are
          79                 :  * clobbered whenever a new frame is pushed. We thus regenerate the loop
          80                 :  * invariant slots after every C++ and scripted call, and avoid doing LICM on
          81                 :  * loops which have such calls. This has a nice property that the slots only
          82                 :  * need to be loop invariant wrt the side effects that happen directly in the
          83                 :  * loop; if C++ calls a getter which scribbles on the object properties
          84                 :  * involved in an 'invariant' then we will reload the invariant's new value
          85                 :  * after the call finishes.
          86                 :  */
          87                 :
          88                 : struct TemporaryCopy;
          89                 :
          90                 : enum InvariantArrayKind { DENSE_ARRAY, TYPED_ARRAY };
          91                 :
          92                 : class LoopState : public MacroAssemblerTypedefs
          93           33573 : {
          94                 :     JSContext *cx;
          95                 :     analyze::CrossScriptSSA *ssa;
          96                 :     JSScript *outerScript;
          97                 :     analyze::ScriptAnalysis *outerAnalysis;
          98                 :
          99                 :     Compiler &cc;
         100                 :     FrameState &frame;
         101                 :
         102                 :     /* Basic information about this loop. */
         103                 :     analyze::LoopAnalysis *lifetime;
         104                 :
         105                 :     /* Allocation at the head of the loop, has all loop carried variables. */
         106                 :     RegisterAllocation *alloc;
         107                 :
         108                 :     /*
         109                 :      * Set if this is not a do-while loop and the compiler has advanced past
         110                 :      * the loop's entry point.
         111                 :      */
         112                 :     bool reachedEntryPoint;
         113                 :
         114                 :     /*
         115                 :      * Jump which initially enters the loop. The state is synced when this jump
         116                 :      * occurs, and needs a trampoline generated to load the right registers
         117                 :      * before going to entryTarget.
         118                 :      */
         119                 :     Jump entry;
         120                 :
         121                 :     /* Registers available for loop variables. */
         122                 :     Registers loopRegs;
         123                 :
         124                 :     /* Whether to skip all bounds check hoisting and loop invariant code analysis. */
         125                 :     bool skipAnalysis;
         126                 :
         127                 :     /* Prior stub rejoins to patch when new loop registers are allocated. */
         128          624191 :     struct StubJoin {
         129                 :         unsigned index;
         130                 :         bool script;
         131                 :     };
         132                 :     Vector<StubJoin,16,CompilerAllocPolicy> loopJoins;
         133                 :
         134                 :     /* Pending loads to patch for stub rejoins. */
         135          171235 :     struct StubJoinPatch {
         136                 :         StubJoin join;
         137                 :         Address address;
         138                 :         AnyRegisterID reg;
         139                 :     };
         140                 :     Vector<StubJoinPatch,16,CompilerAllocPolicy> loopPatches;
         141                 :
         142                 :     /*
         143                 :      * Pair of a jump/label immediately after each call in the loop, to patch
         144                 :      * with restores of the loop invariant stack values.
         145                 :      */
         146          104344 :     struct RestoreInvariantCall {
         147                 :         Jump jump;
         148                 :         Label label;
         149                 :         bool ool;
         150                 :         bool entry;
         151                 :         unsigned patchIndex;  /* Index into Compiler's callSites. */
         152                 :
         153                 :         /* Any copies of temporaries on the stack */
         154                 :         Vector<TemporaryCopy> *temporaryCopies;
         155                 :     };
         156                 :     Vector<RestoreInvariantCall> restoreInvariantCalls;
         157                 :
         158                 :     /*
         159                 :      * Aggregate structure for all loop invariant code and hoisted checks we
         160                 :      * can perform. These are all stored in the same vector as they may depend
         161                 :      * on each other and we need to emit code restoring them in order.
         162                 :      */
         163            4100 :     struct InvariantEntry {
         164                 :         enum EntryKind {
         165                 :             /*
         166                 :              * initializedLength(array) > value1 + value2 + constant.
         167                 :              * Unsigned comparison, so will fail if value + constant < 0
         168                 :              */
         169                 :             DENSE_ARRAY_BOUNDS_CHECK,
         170                 :             TYPED_ARRAY_BOUNDS_CHECK,
         171                 :
         172                 :             /* value1 + constant >= 0 */
         173                 :             NEGATIVE_CHECK,
         174                 :
         175                 :             /* constant >= value1 + value2 */
         176                 :             RANGE_CHECK,
         177                 :
         178                 :             /* For dense arrays */
         179                 :             DENSE_ARRAY_SLOTS,
         180                 :             DENSE_ARRAY_LENGTH,
         181                 :
         182                 :             /* For typed arrays */
         183                 :             TYPED_ARRAY_SLOTS,
         184                 :             TYPED_ARRAY_LENGTH,
         185                 :
         186                 :             /* For lazy arguments */
         187                 :             INVARIANT_ARGS_BASE,
         188                 :             INVARIANT_ARGS_LENGTH,
         189                 :
         190                 :             /* For definite properties */
         191                 :             INVARIANT_PROPERTY
         192                 :         } kind;
         193                 :         union {
         194                 :             struct {
         195                 :                 uint32_t arraySlot;
         196                 :                 uint32_t valueSlot1;
         197                 :                 uint32_t valueSlot2;
         198                 :                 int32_t constant;
         199                 :             } check;
         200                 :             struct {
         201                 :                 uint32_t arraySlot;
         202                 :                 uint32_t temporary;
         203                 :             } array;
         204                 :             struct {
         205                 :                 uint32_t objectSlot;
         206                 :                 uint32_t propertySlot;
         207                 :                 uint32_t temporary;
         208                 :                 jsid id;
         209                 :             } property;
         210                 :         } u;
         211            4468 :         InvariantEntry() { PodZero(this); }
         212           14733 :         bool isBoundsCheck() const {
         213           14733 :             return kind == DENSE_ARRAY_BOUNDS_CHECK || kind == TYPED_ARRAY_BOUNDS_CHECK;
         214                 :         }
         215           13602 :         bool isCheck() const {
         216           13602 :             return isBoundsCheck() || kind == NEGATIVE_CHECK || kind == RANGE_CHECK;
         217                 :         }
         218                 :     };
         219                 :     Vector<InvariantEntry, 4, CompilerAllocPolicy> invariantEntries;
         220                 :
         221                 :     static inline bool entryRedundant(const InvariantEntry &e0, const InvariantEntry &e1);
         222                 :     bool checkRedundantEntry(const InvariantEntry &entry);
         223                 :
         224                 :     bool loopInvariantEntry(uint32_t slot);
         225                 :     bool addHoistedCheck(InvariantArrayKind arrayKind, uint32_t arraySlot,
         226                 :                          uint32_t valueSlot1, uint32_t valueSlot2, int32_t constant);
         227                 :     void addNegativeCheck(uint32_t valueSlot, int32_t constant);
         228                 :     void addRangeCheck(uint32_t valueSlot1, uint32_t valueSlot2, int32_t constant);
         229                 :     bool hasTestLinearRelationship(uint32_t slot);
         230                 :
         231           33560 :     bool hasInvariants() { return !invariantEntries.empty(); }
         232                 :     void restoreInvariants(jsbytecode *pc, Assembler &masm,
         233                 :                            Vector<TemporaryCopy> *temporaryCopies, Vector<Jump> *jumps);
         234                 :
         235                 :   public:
         236                 :
         237                 :     /* Outer loop to this one, in case of loop nesting. */
         238                 :     LoopState *outer;
         239                 :
         240                 :     /* Offset from the outermost frame at which temporaries should be allocated. */
         241                 :     uint32_t temporariesStart;
         242                 :
         243                 :     LoopState(JSContext *cx, analyze::CrossScriptSSA *ssa,
         244                 :               Compiler *cc, FrameState *frame);
         245                 :     bool init(jsbytecode *head, Jump entry, jsbytecode *entryTarget);
         246                 :
         247          926923 :     void setOuterPC(jsbytecode *pc)
         248                 :     {
         249          926923 :         if (uint32_t(pc - outerScript->code) == lifetime->entry && lifetime->entry != lifetime->head)
         250           33491 :             reachedEntryPoint = true;
         251          926923 :     }
         252                 :
         253          715442 :     bool generatingInvariants() { return !skipAnalysis; }
         254                 :
         255                 :     /* Add a call with trailing jump/label, after which invariants need to be restored. */
         256                 :     void addInvariantCall(Jump jump, Label label, bool ool, bool entry, unsigned patchIndex, Uses uses);
         257                 :
         258           93838 :     uint32_t headOffset() { return lifetime->head; }
         259          123570 :     uint32_t getLoopRegs() { return loopRegs.freeMask; }
         260                 :
         261           33560 :     Jump entryJump() { return entry; }
         262           33560 :     uint32_t entryOffset() { return lifetime->entry; }
         263            1295 :     uint32_t backedgeOffset() { return lifetime->backedge; }
         264                 :
         265                 :     /* Whether the payload of slot is carried around the loop in a register. */
         266             905 :     bool carriesLoopReg(FrameEntry *fe) { return alloc->hasAnyReg(frame.entrySlot(fe)); }
         267                 :
         268                 :     void setLoopReg(AnyRegisterID reg, FrameEntry *fe);
         269                 :
         270          864688 :     void clearLoopReg(AnyRegisterID reg)
         271                 :     {
         272                 :         /*
         273                 :          * Mark reg as having been modified since the start of the loop; it
         274                 :          * cannot subsequently be marked to carry a register around the loop.
         275                 :          */
         276          864688 :         JS_ASSERT(loopRegs.hasReg(reg) == alloc->loop(reg));
         277          864688 :         if (loopRegs.hasReg(reg)) {
         278          136281 :             loopRegs.takeReg(reg);
         279          136281 :             alloc->setUnassigned(reg);
         280          136281 :             JaegerSpew(JSpew_Regalloc, "clearing loop register %s\n", reg.name());
         281                 :         }
         282          864688 :     }
         283                 :
         284                 :     void addJoin(unsigned index, bool script);
         285                 :     void clearLoopRegisters();
         286                 :
         287                 :     void flushLoop(StubCompiler &stubcc);
         288                 :
         289                 :     /*
         290                 :      * These should only be used for entries which are known to be dense arrays
         291                 :      * (if they are objects at all).
         292                 :      */
         293                 :     bool hoistArrayLengthCheck(InvariantArrayKind arrayKind,
         294                 :                                const analyze::CrossSSAValue &obj,
         295                 :                                const analyze::CrossSSAValue &index);
         296                 :     FrameEntry *invariantArraySlots(const analyze::CrossSSAValue &obj);
         297                 :
         298                 :     /* Methods for accesses on lazy arguments. */
         299                 :     bool hoistArgsLengthCheck(const analyze::CrossSSAValue &index);
         300                 :     FrameEntry *invariantArguments();
         301                 :
         302                 :     FrameEntry *invariantLength(const analyze::CrossSSAValue &obj);
         303                 :     FrameEntry *invariantProperty(const analyze::CrossSSAValue &obj, jsid id);
         304                 :
         305                 :     /* Whether a binary or inc/dec op's result cannot overflow. */
         306                 :     bool cannotIntegerOverflow(const analyze::CrossSSAValue &pushed);
         307                 :
         308                 :     /*
         309                 :      * Whether integer overflow in addition or negative zeros in multiplication
         310                 :      * at a binary op can be safely ignored.
         311                 :      */
         312                 :     bool ignoreIntegerOverflow(const analyze::CrossSSAValue &pushed);
         313                 :
         314                 :   private:
         315                 :     /* Analysis information for the loop. */
         316                 :
         317                 :     /*
         318                 :      * Any inequality known to hold at the head of the loop. This has the
         319                 :      * form 'lhs <= rhs + constant' or 'lhs >= rhs + constant', depending on
         320                 :      * lessEqual. The lhs may be modified within the loop body (the test is
         321                 :      * invalid afterwards), and the rhs is invariant. This information is only
         322                 :      * valid if the LHS/RHS are known integers.
         323                 :      */
         324                 :     enum { UNASSIGNED = UINT32_MAX };
         325                 :     uint32_t testLHS;
         326                 :     uint32_t testRHS;
         327                 :     int32_t testConstant;
         328                 :     bool testLessEqual;
         329                 :
         330                 :     /*
         331                 :      * A variable which will be incremented or decremented exactly once in each
         332                 :      * iteration of the loop. The offset of the operation is indicated, which
         333                 :      * may or may not run after the initial entry into the loop.
         334                 :      */
         335            9894 :     struct Increment {
         336                 :         uint32_t slot;
         337                 :         uint32_t offset;
         338                 :     };
         339                 :     Vector<Increment, 4, CompilerAllocPolicy> increments;
         340                 :
         341                 :     /* It is unknown which arrays grow or which objects are modified in this loop. */
         342                 :     bool unknownModset;
         343                 :
         344                 :     /*
         345                 :      * Arrays which might grow during this loop. This is a guess, and may
         346                 :      * underapproximate the actual set of such arrays.
         347                 :      */
         348                 :     Vector<types::TypeObject *, 4, CompilerAllocPolicy> growArrays;
         349                 :
         350                 :     /* Properties which might be modified during this loop. */
         351            4719 :     struct ModifiedProperty {
         352                 :         types::TypeObject *object;
         353                 :         jsid id;
         354                 :     };
         355                 :     Vector<ModifiedProperty, 4, CompilerAllocPolicy> modifiedProperties;
         356                 :
         357                 :     /*
         358                 :      * Whether this loop only performs integer and double arithmetic and dense
         359                 :      * array accesses. Integer overflows in this loop which only flow to bitops
         360                 :      * can be ignored.
         361                 :      */
         362                 :     bool constrainedLoop;
         363                 :
         364                 :     void analyzeLoopTest();
         365                 :     void analyzeLoopIncrements();
         366                 :     void analyzeLoopBody(unsigned frame);
         367                 :
         368                 :     bool definiteArrayAccess(const analyze::SSAValue &obj, const analyze::SSAValue &index);
         369                 :     bool getLoopTestAccess(const analyze::SSAValue &v, uint32_t *pslot, int32_t *pconstant);
         370                 :
         371                 :     bool addGrowArray(types::TypeObject *object);
         372                 :     bool addModifiedProperty(types::TypeObject *object, jsid id);
         373                 :
         374                 :     bool hasGrowArray(types::TypeObject *object);
         375                 :     bool hasModifiedProperty(types::TypeObject *object, jsid id);
         376                 :
         377                 :     uint32_t getIncrement(uint32_t slot);
         378                 :     int32_t adjustConstantForIncrement(jsbytecode *pc, uint32_t slot);
         379                 :
         380                 :     bool getEntryValue(const analyze::CrossSSAValue &v, uint32_t *pslot, int32_t *pconstant);
         381                 :     bool computeInterval(const analyze::CrossSSAValue &v, int32_t *pmin, int32_t *pmax);
         382                 :     bool valueFlowsToBitops(const analyze::SSAValue &v);
         383                 : };
         384                 :
         385                 : } /* namespace mjit */
         386                 : } /* namespace js */
         387                 :
         388                 : #endif /* jsjaeger_loopstate_h__ */

Generated by: LCOV version 1.7