LCOV - code coverage report
Current view: top level - js/src/jit - MIRGraph.h (source / functions) Hit Total Coverage
Test: output.info Lines: 351 373 94.1 %
Date: 2017-07-14 16:53:18 Functions: 125 132 94.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_MIRGraph_h
       8             : #define jit_MIRGraph_h
       9             : 
      10             : // This file declares the data structures used to build a control-flow graph
      11             : // containing MIR.
      12             : 
      13             : #include "jit/FixedList.h"
      14             : #include "jit/JitAllocPolicy.h"
      15             : #include "jit/MIR.h"
      16             : 
      17             : namespace js {
      18             : namespace jit {
      19             : 
      20             : class BytecodeAnalysis;
      21             : class MBasicBlock;
      22             : class MIRGraph;
      23             : class MStart;
      24             : 
      25             : class MDefinitionIterator;
      26             : 
      27             : typedef InlineListIterator<MInstruction> MInstructionIterator;
      28             : typedef InlineListReverseIterator<MInstruction> MInstructionReverseIterator;
      29             : typedef InlineListIterator<MPhi> MPhiIterator;
      30             : 
      31             : #ifdef DEBUG
      32             : typedef InlineForwardListIterator<MResumePoint> MResumePointIterator;
      33             : #endif
      34             : 
      35             : class LBlock;
      36             : 
      37             : class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
      38             : {
      39             :   public:
      40             :     enum Kind {
      41             :         NORMAL,
      42             :         PENDING_LOOP_HEADER,
      43             :         LOOP_HEADER,
      44             :         SPLIT_EDGE,
      45             :         DEAD
      46             :     };
      47             : 
      48             :   private:
      49             :     MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind);
      50             :     MOZ_MUST_USE bool init();
      51             :     void copySlots(MBasicBlock* from);
      52             :     MOZ_MUST_USE bool inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred,
      53             :                                         uint32_t popped, unsigned stackPhiCount = 0);
      54             :     MOZ_MUST_USE bool inheritResumePoint(MBasicBlock* pred);
      55             :     void assertUsesAreNotWithin(MUseIterator use, MUseIterator end);
      56             : 
      57             :     // This block cannot be reached by any means.
      58             :     bool unreachable_;
      59             : 
      60             :     // Keeps track if the phis has been type specialized already.
      61             :     bool specialized_;
      62             : 
      63             :     // Pushes a copy of a local variable or argument.
      64             :     void pushVariable(uint32_t slot);
      65             : 
      66             :     // Sets a variable slot to the top of the stack, correctly creating copies
      67             :     // as needed.
      68             :     void setVariable(uint32_t slot);
      69             : 
      70             :     enum ReferencesType {
      71             :         RefType_None = 0,
      72             : 
      73             :         // Assert that the instruction is unused.
      74             :         RefType_AssertNoUses = 1 << 0,
      75             : 
      76             :         // Discard the operands of the resume point / instructions if the
      77             :         // following flag are given too.
      78             :         RefType_DiscardOperands = 1 << 1,
      79             :         RefType_DiscardResumePoint = 1 << 2,
      80             :         RefType_DiscardInstruction = 1 << 3,
      81             : 
      82             :         // Discard operands of the instruction and its resume point.
      83             :         RefType_DefaultNoAssert = RefType_DiscardOperands |
      84             :                                   RefType_DiscardResumePoint |
      85             :                                   RefType_DiscardInstruction,
      86             : 
      87             :         // Discard everything and assert that the instruction is not used.
      88             :         RefType_Default = RefType_AssertNoUses | RefType_DefaultNoAssert,
      89             : 
      90             :         // Discard resume point operands only, without discarding the operands
      91             :         // of the current instruction.  Asserts that the instruction is unused.
      92             :         RefType_IgnoreOperands = RefType_AssertNoUses |
      93             :                                  RefType_DiscardOperands |
      94             :                                  RefType_DiscardResumePoint
      95             :     };
      96             : 
      97             :     void discardResumePoint(MResumePoint* rp, ReferencesType refType = RefType_Default);
      98             : 
      99             :     // Remove all references to an instruction such that it can be removed from
     100             :     // the list of instruction, without keeping any dangling pointer to it. This
     101             :     // includes the operands of the instruction, and the resume point if
     102             :     // present.
     103             :     void prepareForDiscard(MInstruction* ins, ReferencesType refType = RefType_Default);
     104             : 
     105             :   public:
     106             :     ///////////////////////////////////////////////////////
     107             :     ////////// BEGIN GRAPH BUILDING INSTRUCTIONS //////////
     108             :     ///////////////////////////////////////////////////////
     109             : 
     110             :     // Creates a new basic block for a MIR generator. If |pred| is not nullptr,
     111             :     // its slots and stack depth are initialized from |pred|.
     112             :     static MBasicBlock* New(MIRGraph& graph, BytecodeAnalysis* analysis, const CompileInfo& info,
     113             :                             MBasicBlock* pred, BytecodeSite* site, Kind kind);
     114             :     static MBasicBlock* New(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, Kind kind);
     115             :     static MBasicBlock* NewPopN(MIRGraph& graph, const CompileInfo& info,
     116             :                                 MBasicBlock* pred, BytecodeSite* site, Kind kind, uint32_t popn);
     117             :     static MBasicBlock* NewWithResumePoint(MIRGraph& graph, const CompileInfo& info,
     118             :                                            MBasicBlock* pred, BytecodeSite* site,
     119             :                                            MResumePoint* resumePoint);
     120             :     static MBasicBlock* NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info,
     121             :                                              MBasicBlock* pred, BytecodeSite* site,
     122             :                                              unsigned loopStateSlots);
     123             :     static MBasicBlock* NewSplitEdge(MIRGraph& graph, MBasicBlock* pred,
     124             :                                      size_t predEdgeIdx, MBasicBlock* succ);
     125             : 
     126      274176 :     bool dominates(const MBasicBlock* other) const {
     127      274176 :         return other->domIndex() - domIndex() < numDominated();
     128             :     }
     129             : 
     130        8965 :     void setId(uint32_t id) {
     131        8965 :         id_ = id;
     132        8965 :     }
     133             : 
     134             :     // Mark this block (and only this block) as unreachable.
     135          70 :     void setUnreachable() {
     136          70 :         MOZ_ASSERT(!unreachable_);
     137          70 :         setUnreachableUnchecked();
     138          70 :     }
     139          70 :     void setUnreachableUnchecked() {
     140          70 :         unreachable_ = true;
     141          70 :     }
     142        5469 :     bool unreachable() const {
     143        5469 :         return unreachable_;
     144             :     }
     145             :     // Move the definition to the top of the stack.
     146             :     void pick(int32_t depth);
     147             : 
     148             :     // Move the top of the stack definition under the depth-th stack value.
     149             :     void unpick(int32_t depth);
     150             : 
     151             :     // Exchange 2 stack slots at the defined depth
     152             :     void swapAt(int32_t depth);
     153             : 
     154             :     // Gets the instruction associated with various slot types.
     155             :     MDefinition* peek(int32_t depth);
     156             : 
     157             :     MDefinition* environmentChain();
     158             :     MDefinition* argumentsObject();
     159             : 
     160             :     // Increase the number of slots available
     161             :     MOZ_MUST_USE bool increaseSlots(size_t num);
     162             :     MOZ_MUST_USE bool ensureHasSlots(size_t num);
     163             : 
     164             :     // Initializes a slot value; must not be called for normal stack
     165             :     // operations, as it will not create new SSA names for copies.
     166             :     void initSlot(uint32_t index, MDefinition* ins);
     167             : 
     168             :     // Discard the slot at the given depth, lowering all slots above.
     169             :     void shimmySlots(int discardDepth);
     170             : 
     171             :     // In an OSR block, set all MOsrValues to use the MResumePoint attached to
     172             :     // the MStart.
     173             :     MOZ_MUST_USE bool linkOsrValues(MStart* start);
     174             : 
     175             :     // Sets the instruction associated with various slot types. The
     176             :     // instruction must lie at the top of the stack.
     177             :     void setLocal(uint32_t local);
     178             :     void setArg(uint32_t arg);
     179             :     void setSlot(uint32_t slot);
     180             :     void setSlot(uint32_t slot, MDefinition* ins);
     181             : 
     182             :     // Rewrites a slot directly, bypassing the stack transition. This should
     183             :     // not be used under most circumstances.
     184             :     void rewriteSlot(uint32_t slot, MDefinition* ins);
     185             : 
     186             :     // Rewrites a slot based on its depth (same as argument to peek()).
     187             :     void rewriteAtDepth(int32_t depth, MDefinition* ins);
     188             : 
     189             :     // Tracks an instruction as being pushed onto the operand stack.
     190             :     void push(MDefinition* ins);
     191             :     void pushArg(uint32_t arg);
     192             :     void pushLocal(uint32_t local);
     193             :     void pushSlot(uint32_t slot);
     194             :     void setEnvironmentChain(MDefinition* ins);
     195             :     void setArgumentsObject(MDefinition* ins);
     196             : 
     197             :     // Returns the top of the stack, then decrements the virtual stack pointer.
     198             :     MDefinition* pop();
     199             :     void popn(uint32_t n);
     200             : 
     201             :     // Adds an instruction to this block's instruction list.
     202             :     void add(MInstruction* ins);
     203             : 
     204             :     // Marks the last instruction of the block; no further instructions
     205             :     // can be added.
     206             :     void end(MControlInstruction* ins);
     207             : 
     208             :     // Adds a phi instruction, but does not set successorWithPhis.
     209             :     void addPhi(MPhi* phi);
     210             : 
     211             :     // Adds a resume point to this block.
     212        8996 :     void addResumePoint(MResumePoint* resume) {
     213             : #ifdef DEBUG
     214        8996 :         resumePoints_.pushFront(resume);
     215             : #endif
     216        8996 :     }
     217             : 
     218             :     // Discard pre-allocated resume point.
     219           0 :     void discardPreAllocatedResumePoint(MResumePoint* resume) {
     220           0 :         MOZ_ASSERT(!resume->instruction());
     221           0 :         discardResumePoint(resume);
     222           0 :     }
     223             : 
     224             :     // Adds a predecessor. Every predecessor must have the same exit stack
     225             :     // depth as the entry state to this block. Adding a predecessor
     226             :     // automatically creates phi nodes and rewrites uses as needed.
     227             :     MOZ_MUST_USE bool addPredecessor(TempAllocator& alloc, MBasicBlock* pred);
     228             :     MOZ_MUST_USE bool addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped);
     229             : 
     230             :     // Add a predecessor which won't introduce any new phis to this block.
     231             :     // This may be called after the contents of this block have been built.
     232             :     void addPredecessorSameInputsAs(MBasicBlock* pred, MBasicBlock* existingPred);
     233             : 
     234             :     // Stranger utilities used for inlining.
     235             :     MOZ_MUST_USE bool addPredecessorWithoutPhis(MBasicBlock* pred);
     236             :     void inheritSlots(MBasicBlock* parent);
     237             :     MOZ_MUST_USE bool initEntrySlots(TempAllocator& alloc);
     238             : 
     239             :     // Replaces an edge for a given block with a new block. This is
     240             :     // used for critical edge splitting.
     241             :     //
     242             :     // Note: If successorWithPhis is set, you must not be replacing it.
     243             :     void replacePredecessor(MBasicBlock* old, MBasicBlock* split);
     244             :     void replaceSuccessor(size_t pos, MBasicBlock* split);
     245             : 
     246             :     // Removes `pred` from the predecessor list. If this block defines phis,
     247             :     // removes the entry for `pred` and updates the indices of later entries.
     248             :     // This may introduce redundant phis if the new block has fewer
     249             :     // than two predecessors.
     250             :     void removePredecessor(MBasicBlock* pred);
     251             : 
     252             :     // A version of removePredecessor which expects that phi operands to
     253             :     // |pred| have already been removed.
     254             :     void removePredecessorWithoutPhiOperands(MBasicBlock* pred, size_t predIndex);
     255             : 
     256             :     // Resets all the dominator info so that it can be recomputed.
     257             :     void clearDominatorInfo();
     258             : 
     259             :     // Sets a back edge. This places phi nodes and rewrites instructions within
     260             :     // the current loop as necessary. If the backedge introduces new types for
     261             :     // phis at the loop header, returns a disabling abort.
     262             :     MOZ_MUST_USE AbortReason setBackedge(TempAllocator& alloc, MBasicBlock* block);
     263             :     MOZ_MUST_USE bool setBackedgeWasm(MBasicBlock* block);
     264             : 
     265             :     // Resets a LOOP_HEADER block to a NORMAL block.  This is needed when
     266             :     // optimizations remove the backedge.
     267             :     void clearLoopHeader();
     268             : 
     269             :     // Sets a block to a LOOP_HEADER block, with newBackedge as its backedge.
     270             :     // This is needed when optimizations remove the normal entry to a loop
     271             :     // with multiple entries.
     272             :     void setLoopHeader(MBasicBlock* newBackedge);
     273             : 
     274             :     // Propagates phis placed in a loop header down to this successor block.
     275             :     void inheritPhis(MBasicBlock* header);
     276             : 
     277             :     // Propagates backedge slots into phis operands of the loop header.
     278             :     MOZ_MUST_USE bool inheritPhisFromBackedge(TempAllocator& alloc, MBasicBlock* backedge,
     279             :                                               bool* hadTypeChange);
     280             : 
     281             :     // Compute the types for phis in this block according to their inputs.
     282             :     MOZ_MUST_USE bool specializePhis(TempAllocator& alloc);
     283             : 
     284             :     void insertBefore(MInstruction* at, MInstruction* ins);
     285             :     void insertAfter(MInstruction* at, MInstruction* ins);
     286             : 
     287             :     void insertAtEnd(MInstruction* ins);
     288             : 
     289             :     // Add an instruction to this block, from elsewhere in the graph.
     290             :     void addFromElsewhere(MInstruction* ins);
     291             : 
     292             :     // Move an instruction. Movement may cross block boundaries.
     293             :     void moveBefore(MInstruction* at, MInstruction* ins);
     294             : 
     295             :     enum IgnoreTop {
     296             :         IgnoreNone = 0,
     297             :         IgnoreRecover = 1 << 0
     298             :     };
     299             : 
     300             :     // Locate the top of the |block|, where it is safe to insert a new
     301             :     // instruction.
     302             :     MInstruction* safeInsertTop(MDefinition* ins = nullptr, IgnoreTop ignore = IgnoreNone);
     303             : 
     304             :     // Removes an instruction with the intention to discard it.
     305             :     void discard(MInstruction* ins);
     306             :     void discardLastIns();
     307             :     void discardDef(MDefinition* def);
     308             :     void discardAllInstructions();
     309             :     void discardAllInstructionsStartingAt(MInstructionIterator iter);
     310             :     void discardAllPhiOperands();
     311             :     void discardAllPhis();
     312             :     void discardAllResumePoints(bool discardEntry = true);
     313             :     void clear();
     314             : 
     315             :     // Same as |void discard(MInstruction* ins)| but assuming that
     316             :     // all operands are already discarded.
     317             :     void discardIgnoreOperands(MInstruction* ins);
     318             : 
     319             :     // Discards a phi instruction and updates predecessor successorWithPhis.
     320             :     void discardPhi(MPhi* phi);
     321             : 
     322             :     // Some instruction which are guarding against some MIRType value, or
     323             :     // against a type expectation should be considered as removing a potenatial
     324             :     // branch where the guard does not hold.  We need to register such
     325             :     // instructions in order to do destructive optimizations correctly, such as
     326             :     // Range Analysis.
     327             :     void flagOperandsOfPrunedBranches(MInstruction* ins);
     328             : 
     329             :     // Mark this block as having been removed from the graph.
     330         392 :     void markAsDead() {
     331         392 :         MOZ_ASSERT(kind_ != DEAD);
     332         392 :         kind_ = DEAD;
     333         392 :     }
     334             : 
     335             :     ///////////////////////////////////////////////////////
     336             :     /////////// END GRAPH BUILDING INSTRUCTIONS ///////////
     337             :     ///////////////////////////////////////////////////////
     338             : 
     339       68551 :     MIRGraph& graph() {
     340       68551 :         return graph_;
     341             :     }
     342       18978 :     const CompileInfo& info() const {
     343       18978 :         return info_;
     344             :     }
     345        9727 :     jsbytecode* pc() const {
     346        9727 :         return pc_;
     347             :     }
     348       17274 :     uint32_t nslots() const {
     349       17274 :         return slots_.length();
     350             :     }
     351      135882 :     uint32_t id() const {
     352      135882 :         return id_;
     353             :     }
     354      153478 :     uint32_t numPredecessors() const {
     355      153478 :         return predecessors_.length();
     356             :     }
     357             : 
     358      548352 :     uint32_t domIndex() const {
     359      548352 :         MOZ_ASSERT(!isDead());
     360      548352 :         return domIndex_;
     361             :     }
     362        3750 :     void setDomIndex(uint32_t d) {
     363        3750 :         domIndex_ = d;
     364        3750 :     }
     365             : 
     366      104980 :     MBasicBlock* getPredecessor(uint32_t i) const {
     367      104980 :         return predecessors_[i];
     368             :     }
     369          59 :     size_t indexForPredecessor(MBasicBlock* block) const {
     370             :         // This should only be called before critical edge splitting.
     371          59 :         MOZ_ASSERT(!block->successorWithPhis());
     372             : 
     373          91 :         for (size_t i = 0; i < predecessors_.length(); i++) {
     374          91 :             if (predecessors_[i] == block)
     375         118 :                 return i;
     376             :         }
     377           0 :         MOZ_CRASH();
     378             :     }
     379      539901 :     bool hasAnyIns() const {
     380      539901 :         return !instructions_.empty();
     381             :     }
     382      539862 :     bool hasLastIns() const {
     383      539862 :         return hasAnyIns() && instructions_.rbegin()->isControlInstruction();
     384             :     }
     385      514151 :     MControlInstruction* lastIns() const {
     386      514151 :         MOZ_ASSERT(hasLastIns());
     387      514154 :         return instructions_.rbegin()->toControlInstruction();
     388             :     }
     389             :     // Find or allocate an optimized out constant.
     390             :     MConstant* optimizedOutConstant(TempAllocator& alloc);
     391       58414 :     MPhiIterator phisBegin() const {
     392       58414 :         return phis_.begin();
     393             :     }
     394             :     MPhiIterator phisBegin(MPhi* at) const {
     395             :         return phis_.begin(at);
     396             :     }
     397     2116467 :     MPhiIterator phisEnd() const {
     398     2116467 :         return phis_.end();
     399             :     }
     400       19023 :     bool phisEmpty() const {
     401       19023 :         return phis_.empty();
     402             :     }
     403             : #ifdef DEBUG
     404       15325 :     MResumePointIterator resumePointsBegin() const {
     405       15325 :         return resumePoints_.begin();
     406             :     }
     407       40378 :     MResumePointIterator resumePointsEnd() const {
     408       40378 :         return resumePoints_.end();
     409             :     }
     410         392 :     bool resumePointsEmpty() const {
     411         392 :         return resumePoints_.empty();
     412             :     }
     413             : #endif
     414       62152 :     MInstructionIterator begin() {
     415       62152 :         return instructions_.begin();
     416             :     }
     417       14421 :     MInstructionIterator begin(MInstruction* at) {
     418       14421 :         MOZ_ASSERT(at->block() == this);
     419       14421 :         return instructions_.begin(at);
     420             :     }
     421       84423 :     MInstructionIterator end() {
     422       84423 :         return instructions_.end();
     423             :     }
     424        2419 :     MInstructionReverseIterator rbegin() {
     425        2419 :         return instructions_.rbegin();
     426             :     }
     427         684 :     MInstructionReverseIterator rbegin(MInstruction* at) {
     428         684 :         MOZ_ASSERT(at->block() == this);
     429         684 :         return instructions_.rbegin(at);
     430             :     }
     431       11424 :     MInstructionReverseIterator rend() {
     432       11424 :         return instructions_.rend();
     433             :     }
     434       17461 :     bool isLoopHeader() const {
     435       17461 :         return kind_ == LOOP_HEADER;
     436             :     }
     437         784 :     bool hasUniqueBackedge() const {
     438         784 :         MOZ_ASSERT(isLoopHeader());
     439         784 :         MOZ_ASSERT(numPredecessors() >= 2);
     440         784 :         if (numPredecessors() == 2)
     441         784 :             return true;
     442           0 :         if (numPredecessors() == 3) // fixup block added by ValueNumbering phase.
     443           0 :             return getPredecessor(1)->numPredecessors() == 0;
     444           0 :         return false;
     445             :     }
     446         564 :     MBasicBlock* backedge() const {
     447         564 :         MOZ_ASSERT(hasUniqueBackedge());
     448         564 :         return getPredecessor(numPredecessors() - 1);
     449             :     }
     450          30 :     MBasicBlock* loopHeaderOfBackedge() const {
     451          30 :         MOZ_ASSERT(isLoopBackedge());
     452          30 :         return getSuccessor(numSuccessors() - 1);
     453             :     }
     454          53 :     MBasicBlock* loopPredecessor() const {
     455          53 :         MOZ_ASSERT(isLoopHeader());
     456          53 :         return getPredecessor(0);
     457             :     }
     458        2493 :     bool isLoopBackedge() const {
     459        2493 :         if (!numSuccessors())
     460         183 :             return false;
     461        2310 :         MBasicBlock* lastSuccessor = getSuccessor(numSuccessors() - 1);
     462        2525 :         return lastSuccessor->isLoopHeader() &&
     463        2525 :                lastSuccessor->hasUniqueBackedge() &&
     464        2525 :                lastSuccessor->backedge() == this;
     465             :     }
     466          50 :     bool isSplitEdge() const {
     467          50 :         return kind_ == SPLIT_EDGE;
     468             :     }
     469     1047797 :     bool isDead() const {
     470     1047797 :         return kind_ == DEAD;
     471             :     }
     472             : 
     473       65601 :     uint32_t stackDepth() const {
     474       65601 :         return stackPosition_;
     475             :     }
     476           1 :     void setStackDepth(uint32_t depth) {
     477           1 :         stackPosition_ = depth;
     478           1 :     }
     479       38600 :     bool isMarked() const {
     480       38600 :         return mark_;
     481             :     }
     482       12424 :     void mark() {
     483       12424 :         MOZ_ASSERT(!mark_, "Marking already-marked block");
     484       12424 :         markUnchecked();
     485       12424 :     }
     486       12459 :     void markUnchecked() {
     487       12459 :         mark_ = true;
     488       12459 :     }
     489       12409 :     void unmark() {
     490       12409 :         MOZ_ASSERT(mark_, "Unarking unmarked block");
     491       12409 :         unmarkUnchecked();
     492       12409 :     }
     493       12409 :     void unmarkUnchecked() {
     494       12409 :         mark_ = false;
     495       12409 :     }
     496             : 
     497       45054 :     MBasicBlock* immediateDominator() const {
     498       45054 :         return immediateDominator_;
     499             :     }
     500             : 
     501        4132 :     void setImmediateDominator(MBasicBlock* dom) {
     502        4132 :         immediateDominator_ = dom;
     503        4132 :     }
     504             : 
     505             :     MTest* immediateDominatorBranch(BranchDirection* pdirection);
     506             : 
     507       26689 :     size_t numImmediatelyDominatedBlocks() const {
     508       26689 :         return immediatelyDominated_.length();
     509             :     }
     510             : 
     511       19209 :     MBasicBlock* getImmediatelyDominatedBlock(size_t i) const {
     512       19209 :         return immediatelyDominated_[i];
     513             :     }
     514             : 
     515        4153 :     MBasicBlock** immediatelyDominatedBlocksBegin() {
     516        4153 :         return immediatelyDominated_.begin();
     517             :     }
     518             : 
     519        4153 :     MBasicBlock** immediatelyDominatedBlocksEnd() {
     520        4153 :         return immediatelyDominated_.end();
     521             :     }
     522             : 
     523             :     // Return the number of blocks dominated by this block. All blocks
     524             :     // dominate at least themselves, so this will always be non-zero.
     525      302768 :     size_t numDominated() const {
     526      302768 :         MOZ_ASSERT(numDominated_ != 0);
     527      302768 :         return numDominated_;
     528             :     }
     529             : 
     530        7342 :     void addNumDominated(size_t n) {
     531        7342 :         numDominated_ += n;
     532        7342 :     }
     533             : 
     534             :     // Add |child| to this block's immediately-dominated set.
     535             :     bool addImmediatelyDominatedBlock(MBasicBlock* child);
     536             : 
     537             :     // Remove |child| from this block's immediately-dominated set.
     538             :     void removeImmediatelyDominatedBlock(MBasicBlock* child);
     539             : 
     540             :     // This function retrieves the internal instruction associated with a
     541             :     // slot, and should not be used for normal stack operations. It is an
     542             :     // internal helper that is also used to enhance spew.
     543             :     MDefinition* getSlot(uint32_t index);
     544             : 
     545       95266 :     MResumePoint* entryResumePoint() const {
     546       95266 :         return entryResumePoint_;
     547             :     }
     548          49 :     void setEntryResumePoint(MResumePoint* rp) {
     549          49 :         entryResumePoint_ = rp;
     550          49 :     }
     551         441 :     void clearEntryResumePoint() {
     552         441 :         discardResumePoint(entryResumePoint_);
     553         441 :         entryResumePoint_ = nullptr;
     554         441 :     }
     555       38541 :     MResumePoint* outerResumePoint() const {
     556       38541 :         return outerResumePoint_;
     557             :     }
     558          33 :     void setOuterResumePoint(MResumePoint* outer) {
     559          33 :         MOZ_ASSERT(!outerResumePoint_);
     560          33 :         outerResumePoint_ = outer;
     561          33 :     }
     562           9 :     void clearOuterResumePoint() {
     563           9 :         discardResumePoint(outerResumePoint_);
     564           9 :         outerResumePoint_ = nullptr;
     565           9 :     }
     566        4527 :     MResumePoint* callerResumePoint() const {
     567        4527 :         return callerResumePoint_;
     568             :     }
     569          67 :     void setCallerResumePoint(MResumePoint* caller) {
     570          67 :         callerResumePoint_ = caller;
     571          67 :     }
     572         733 :     size_t numEntrySlots() const {
     573         733 :         return entryResumePoint()->stackDepth();
     574             :     }
     575         733 :     MDefinition* getEntrySlot(size_t i) const {
     576         733 :         MOZ_ASSERT(i < numEntrySlots());
     577         733 :         return entryResumePoint()->getOperand(i);
     578             :     }
     579             : 
     580       25306 :     LBlock* lir() const {
     581       25306 :         return lir_;
     582             :     }
     583         403 :     void assignLir(LBlock* lir) {
     584         403 :         MOZ_ASSERT(!lir_);
     585         403 :         lir_ = lir;
     586         403 :     }
     587             : 
     588       14984 :     MBasicBlock* successorWithPhis() const {
     589       14984 :         return successorWithPhis_;
     590             :     }
     591        3212 :     uint32_t positionInPhiSuccessor() const {
     592        3212 :         MOZ_ASSERT(successorWithPhis());
     593        3212 :         return positionInPhiSuccessor_;
     594             :     }
     595         173 :     void setSuccessorWithPhis(MBasicBlock* successor, uint32_t id) {
     596         173 :         successorWithPhis_ = successor;
     597         173 :         positionInPhiSuccessor_ = id;
     598         173 :     }
     599         469 :     void clearSuccessorWithPhis() {
     600         469 :         successorWithPhis_ = nullptr;
     601         469 :     }
     602             :     size_t numSuccessors() const;
     603             :     MBasicBlock* getSuccessor(size_t index) const;
     604             :     size_t getSuccessorIndex(MBasicBlock*) const;
     605             :     size_t getPredecessorIndex(MBasicBlock*) const;
     606             : 
     607        6555 :     void setLoopDepth(uint32_t loopDepth) {
     608        6555 :         loopDepth_ = loopDepth;
     609        6555 :     }
     610          17 :     uint32_t loopDepth() const {
     611          17 :         return loopDepth_;
     612             :     }
     613             : 
     614           1 :     bool strict() const {
     615           1 :         return info_.script()->strict();
     616             :     }
     617             : 
     618             :     void dumpStack(GenericPrinter& out);
     619             :     void dumpStack();
     620             : 
     621             :     void dump(GenericPrinter& out);
     622             :     void dump();
     623             : 
     624             :     // Hit count
     625             :     enum class HitState {
     626             :         // Not hit information is attached to this basic block.
     627             :         NotDefined,
     628             : 
     629             :         // The hit information is a raw counter. Note that due to inlining this
     630             :         // counter is not guaranteed to be consistent over the graph.
     631             :         Count,
     632             : 
     633             :         // The hit information is a frequency, which is a form of normalized
     634             :         // counter, where a hit-count can be compared against any previous block
     635             :         // in the graph.
     636             :         Frequency
     637             :     };
     638         724 :     HitState getHitState() const {
     639         724 :         return hitState_;
     640             :     }
     641         924 :     void setHitCount(uint64_t count) {
     642         924 :         hitCount_ = count;
     643         924 :         hitState_ = HitState::Count;
     644         924 :     }
     645         693 :     uint64_t getHitCount() const {
     646         693 :         MOZ_ASSERT(hitState_ == HitState::Count);
     647         693 :         return hitCount_;
     648             :     }
     649             : 
     650             :     // Track bailouts by storing the current pc in MIR instruction added at
     651             :     // this cycle. This is also used for tracking calls and optimizations when
     652             :     // profiling.
     653       19119 :     void updateTrackedSite(BytecodeSite* site) {
     654       19119 :         MOZ_ASSERT(site->tree() == trackedSite_->tree());
     655       19119 :         trackedSite_ = site;
     656       19119 :     }
     657       12910 :     BytecodeSite* trackedSite() const {
     658       12910 :         return trackedSite_;
     659             :     }
     660           0 :     jsbytecode* trackedPc() const {
     661           0 :         return trackedSite_ ? trackedSite_->pc() : nullptr;
     662             :     }
     663         384 :     InlineScriptTree* trackedTree() const {
     664         384 :         return trackedSite_ ? trackedSite_->tree() : nullptr;
     665             :     }
     666             : 
     667             :     // This class is used for reverting the graph within IonBuilder.
     668             :     class BackupPoint {
     669             :         friend MBasicBlock;
     670             : 
     671             :         MBasicBlock* current_;
     672             :         MInstruction* lastIns_;
     673             :         uint32_t stackPosition_;
     674             :         FixedList<MDefinition*> slots_;
     675             : #ifdef DEBUG
     676             :         // The following fields should remain identical during IonBuilder
     677             :         // construction, these are used for assertions.
     678             :         MPhi* lastPhi_;
     679             :         uintptr_t predecessorsCheckSum_;
     680             :         HashNumber instructionsCheckSum_;
     681             :         uint32_t id_;
     682             :         MResumePoint* callerResumePoint_;
     683             :         MResumePoint* entryResumePoint_;
     684             : 
     685             :         size_t computePredecessorsCheckSum(MBasicBlock* block);
     686             :         HashNumber computeInstructionsCheckSum(MBasicBlock* block);
     687             : #endif
     688             :       public:
     689             :         explicit BackupPoint(MBasicBlock* current);
     690             :         MOZ_MUST_USE bool init(TempAllocator& alloc);
     691             :         MBasicBlock* restore();
     692             :     };
     693             : 
     694             :     friend BackupPoint;
     695             : 
     696             :   private:
     697             :     MIRGraph& graph_;
     698             :     const CompileInfo& info_; // Each block originates from a particular script.
     699             :     InlineList<MInstruction> instructions_;
     700             :     Vector<MBasicBlock*, 1, JitAllocPolicy> predecessors_;
     701             :     InlineList<MPhi> phis_;
     702             :     FixedList<MDefinition*> slots_;
     703             :     uint32_t stackPosition_;
     704             :     uint32_t id_;
     705             :     uint32_t domIndex_; // Index in the dominator tree.
     706             :     uint32_t numDominated_;
     707             :     jsbytecode* pc_;
     708             :     LBlock* lir_;
     709             : 
     710             :     // Copy of a dominator block's outerResumePoint_ which holds the state of
     711             :     // caller frame at the time of the call. If not null, this implies that this
     712             :     // basic block corresponds to an inlined script.
     713             :     MResumePoint* callerResumePoint_;
     714             : 
     715             :     // Resume point holding baseline-like frame for the PC corresponding to the
     716             :     // entry of this basic block.
     717             :     MResumePoint* entryResumePoint_;
     718             : 
     719             :     // Resume point holding baseline-like frame for the PC corresponding to the
     720             :     // beginning of the call-site which is being inlined after this block.
     721             :     MResumePoint* outerResumePoint_;
     722             : 
     723             : #ifdef DEBUG
     724             :     // Unordered list used to verify that all the resume points which are
     725             :     // registered are correctly removed when a basic block is removed.
     726             :     InlineForwardList<MResumePoint> resumePoints_;
     727             : #endif
     728             : 
     729             :     MBasicBlock* successorWithPhis_;
     730             :     uint32_t positionInPhiSuccessor_;
     731             :     uint32_t loopDepth_;
     732             :     Kind kind_ : 8;
     733             : 
     734             :     // Utility mark for traversal algorithms.
     735             :     bool mark_;
     736             : 
     737             :     Vector<MBasicBlock*, 1, JitAllocPolicy> immediatelyDominated_;
     738             :     MBasicBlock* immediateDominator_;
     739             : 
     740             :     BytecodeSite* trackedSite_;
     741             : 
     742             :     // Record the number of times a block got visited. Note, due to inlined
     743             :     // scripts these numbers might not be continuous.
     744             :     uint64_t hitCount_;
     745             :     HitState hitState_;
     746             : 
     747             : #if defined(JS_ION_PERF) || defined(DEBUG)
     748             :     unsigned lineno_;
     749             :     unsigned columnIndex_;
     750             : 
     751             :   public:
     752             :     void setLineno(unsigned l) { lineno_ = l; }
     753           0 :     unsigned lineno() const { return lineno_; }
     754             :     void setColumnIndex(unsigned c) { columnIndex_ = c; }
     755           0 :     unsigned columnIndex() const { return columnIndex_; }
     756             : #endif
     757             : };
     758             : 
     759             : typedef InlineListIterator<MBasicBlock> MBasicBlockIterator;
     760             : typedef InlineListIterator<MBasicBlock> ReversePostorderIterator;
     761             : typedef InlineListReverseIterator<MBasicBlock> PostorderIterator;
     762             : 
     763             : typedef Vector<MBasicBlock*, 1, JitAllocPolicy> MIRGraphReturns;
     764             : 
     765             : class MIRGraph
     766             : {
     767             :     InlineList<MBasicBlock> blocks_;
     768             :     TempAllocator* alloc_;
     769             :     MIRGraphReturns* returnAccumulator_;
     770             :     uint32_t blockIdGen_;
     771             :     uint32_t idGen_;
     772             :     MBasicBlock* osrBlock_;
     773             : 
     774             :     size_t numBlocks_;
     775             :     bool hasTryBlock_;
     776             : 
     777             :     InlineList<MPhi> phiFreeList_;
     778             :     size_t phiFreeListLength_;
     779             : 
     780             :   public:
     781         146 :     explicit MIRGraph(TempAllocator* alloc)
     782         146 :       : alloc_(alloc),
     783             :         returnAccumulator_(nullptr),
     784             :         blockIdGen_(0),
     785             :         idGen_(0),
     786             :         osrBlock_(nullptr),
     787             :         numBlocks_(0),
     788             :         hasTryBlock_(false),
     789         146 :         phiFreeListLength_(0)
     790         146 :     { }
     791             : 
     792       41795 :     TempAllocator& alloc() const {
     793       41795 :         return *alloc_;
     794             :     }
     795             : 
     796             :     void addBlock(MBasicBlock* block);
     797             :     void insertBlockAfter(MBasicBlock* at, MBasicBlock* block);
     798             :     void insertBlockBefore(MBasicBlock* at, MBasicBlock* block);
     799             : 
     800             :     void renumberBlocksAfter(MBasicBlock* at);
     801             : 
     802             :     void unmarkBlocks();
     803             : 
     804          66 :     void setReturnAccumulator(MIRGraphReturns* accum) {
     805          66 :         returnAccumulator_ = accum;
     806          66 :     }
     807          33 :     MIRGraphReturns* returnAccumulator() const {
     808          33 :         return returnAccumulator_;
     809             :     }
     810             : 
     811         561 :     MOZ_MUST_USE bool addReturn(MBasicBlock* returnBlock) {
     812         561 :         if (!returnAccumulator_)
     813         500 :             return true;
     814             : 
     815          61 :         return returnAccumulator_->append(returnBlock);
     816             :     }
     817             : 
     818        4909 :     MBasicBlock* entryBlock() {
     819        4909 :         return *blocks_.begin();
     820             :     }
     821         889 :     MBasicBlockIterator begin() {
     822         889 :         return blocks_.begin();
     823             :     }
     824           5 :     MBasicBlockIterator begin(MBasicBlock* at) {
     825           5 :         return blocks_.begin(at);
     826             :     }
     827       40151 :     MBasicBlockIterator end() {
     828       40151 :         return blocks_.end();
     829             :     }
     830         534 :     PostorderIterator poBegin() {
     831         534 :         return blocks_.rbegin();
     832             :     }
     833          15 :     PostorderIterator poBegin(MBasicBlock* at) {
     834          15 :         return blocks_.rbegin(at);
     835             :     }
     836       17420 :     PostorderIterator poEnd() {
     837       17420 :         return blocks_.rend();
     838             :     }
     839         818 :     ReversePostorderIterator rpoBegin() {
     840         818 :         return blocks_.begin();
     841             :     }
     842          59 :     ReversePostorderIterator rpoBegin(MBasicBlock* at) {
     843          59 :         return blocks_.begin(at);
     844             :     }
     845       34901 :     ReversePostorderIterator rpoEnd() {
     846       34901 :         return blocks_.end();
     847             :     }
     848             :     MOZ_MUST_USE bool removeSuccessorBlocks(MBasicBlock* block);
     849             :     void removeBlock(MBasicBlock* block);
     850             :     void removeBlockIncludingPhis(MBasicBlock* block);
     851           4 :     void moveBlockToEnd(MBasicBlock* block) {
     852           4 :         blocks_.remove(block);
     853           4 :         MOZ_ASSERT_IF(!blocks_.empty(), block->id());
     854           4 :         blocks_.pushBack(block);
     855           4 :     }
     856          25 :     void moveBlockBefore(MBasicBlock* at, MBasicBlock* block) {
     857          25 :         MOZ_ASSERT(block->id());
     858          25 :         blocks_.remove(block);
     859          25 :         blocks_.insertBefore(at, block);
     860          25 :     }
     861         945 :     void removeBlockFromList(MBasicBlock* block) {
     862         945 :         blocks_.remove(block);
     863         945 :         numBlocks_--;
     864         945 :     }
     865        1039 :     size_t numBlocks() const {
     866        1039 :         return numBlocks_;
     867             :     }
     868          16 :     uint32_t numBlockIds() const {
     869          16 :         return blockIdGen_;
     870             :     }
     871       24336 :     void allocDefinitionId(MDefinition* ins) {
     872       24336 :         ins->setId(idGen_++);
     873       24336 :     }
     874          40 :     uint32_t getNumInstructionIds() {
     875          40 :         return idGen_;
     876             :     }
     877         278 :     MResumePoint* entryResumePoint() {
     878         278 :         return entryBlock()->entryResumePoint();
     879             :     }
     880             : 
     881             :     void copyIds(const MIRGraph& other) {
     882             :         idGen_ = other.idGen_;
     883             :         blockIdGen_ = other.blockIdGen_;
     884             :         numBlocks_ = other.numBlocks_;
     885             :     }
     886             : 
     887           4 :     void setOsrBlock(MBasicBlock* osrBlock) {
     888           4 :         MOZ_ASSERT(!osrBlock_);
     889           4 :         osrBlock_ = osrBlock;
     890           4 :     }
     891       33710 :     MBasicBlock* osrBlock() {
     892       33710 :         return osrBlock_;
     893             :     }
     894             : 
     895          16 :     bool hasTryBlock() const {
     896          16 :         return hasTryBlock_;
     897             :     }
     898           2 :     void setHasTryBlock() {
     899           2 :         hasTryBlock_ = true;
     900           2 :     }
     901             : 
     902             :     void dump(GenericPrinter& out);
     903             :     void dump();
     904             : 
     905           0 :     void addPhiToFreeList(MPhi* phi) {
     906           0 :         phiFreeList_.pushBack(phi);
     907           0 :         phiFreeListLength_++;
     908           0 :     }
     909           0 :     size_t phiFreeListLength() const {
     910           0 :         return phiFreeListLength_;
     911             :     }
     912           0 :     MPhi* takePhiFromFreeList() {
     913           0 :         MOZ_ASSERT(phiFreeListLength_ > 0);
     914           0 :         phiFreeListLength_--;
     915           0 :         return phiFreeList_.popBack();
     916             :     }
     917             : };
     918             : 
     919             : class MDefinitionIterator
     920             : {
     921             :   friend class MBasicBlock;
     922             :   friend class MNodeIterator;
     923             : 
     924             :   private:
     925             :     MBasicBlock* block_;
     926             :     MPhiIterator phiIter_;
     927             :     MInstructionIterator iter_;
     928             : 
     929     2064824 :     bool atPhi() const {
     930     2064824 :         return phiIter_ != block_->phisEnd();
     931             :     }
     932             : 
     933     1819611 :     MDefinition* getIns() {
     934     1819611 :         if (atPhi())
     935      585256 :             return *phiIter_;
     936     1234417 :         return *iter_;
     937             :     }
     938             : 
     939      171777 :     bool more() const {
     940      171777 :         return atPhi() || (*iter_) != block_->lastIns();
     941             :     }
     942             : 
     943             :   public:
     944       21129 :     explicit MDefinitionIterator(MBasicBlock* block)
     945       21129 :       : block_(block),
     946             :         phiIter_(block->phisBegin()),
     947       21129 :         iter_(block->begin())
     948       21129 :     { }
     949             : 
     950       73781 :     MDefinitionIterator operator ++() {
     951       73781 :         MOZ_ASSERT(more());
     952       73773 :         if (atPhi())
     953        9542 :             ++phiIter_;
     954             :         else
     955       64232 :             ++iter_;
     956       73773 :         return *this;
     957             :     }
     958             : 
     959       73781 :     MDefinitionIterator operator ++(int) {
     960       73781 :         MDefinitionIterator old(*this);
     961       73781 :         operator++ ();
     962       73773 :         return old;
     963             :     }
     964             : 
     965       98006 :     explicit operator bool() const {
     966       98006 :         return more();
     967             :     }
     968             : 
     969      557069 :     MDefinition* operator*() {
     970      557069 :         return getIns();
     971             :     }
     972             : 
     973     1262710 :     MDefinition* operator ->() {
     974     1262710 :         return getIns();
     975             :     }
     976             : };
     977             : 
     978             : // Iterates on all resume points, phis, and instructions of a MBasicBlock.
     979             : // Resume points are visited as long as the instruction which holds it is not
     980             : // discarded.
     981             : class MNodeIterator
     982             : {
     983             :   private:
     984             :     // Last instruction which holds a resume point. To handle the entry point
     985             :     // resume point, it is set to the last instruction, assuming that the last
     986             :     // instruction is not discarded before we visit it.
     987             :     MInstruction* last_;
     988             : 
     989             :     // Definition iterator which is one step ahead when visiting resume points.
     990             :     // This is in order to avoid incrementing the iterator while it is settled
     991             :     // on a discarded instruction.
     992             :     MDefinitionIterator defIter_;
     993             : 
     994        1359 :     MBasicBlock* block() const {
     995        1359 :         return defIter_.block_;
     996             :     }
     997             : 
     998        6234 :     bool atResumePoint() const {
     999        6234 :         return last_ && !last_->isDiscarded();
    1000             :     }
    1001             : 
    1002        2716 :     MNode* getNode() {
    1003        2716 :         if (!atResumePoint())
    1004        2044 :             return *defIter_;
    1005             : 
    1006             :         // We use the last instruction as a sentinelle to iterate over the entry
    1007             :         // resume point of the basic block, before even starting to iterate on
    1008             :         // the instruction list.  Otherwise, the last_ corresponds to the
    1009             :         // previous instruction.
    1010         672 :         if (last_ != block()->lastIns())
    1011         359 :             return last_->resumePoint();
    1012         313 :         return block()->entryResumePoint();
    1013             :     }
    1014             : 
    1015        2716 :     void next() {
    1016        2716 :         if (!atResumePoint()) {
    1017        2044 :             if (defIter_->isInstruction() && defIter_->toInstruction()->resumePoint()) {
    1018             :                 // In theory, we could but in practice this does not happen.
    1019         374 :                 MOZ_ASSERT(*defIter_ != block()->lastIns());
    1020         374 :                 last_ = defIter_->toInstruction();
    1021             :             }
    1022             : 
    1023        2044 :             defIter_++;
    1024             :         } else {
    1025         672 :             last_ = nullptr;
    1026             :         }
    1027        2716 :     }
    1028             : 
    1029        5745 :     bool more() const {
    1030        5745 :         return defIter_ || atResumePoint();
    1031             :     }
    1032             : 
    1033             :   public:
    1034         313 :     explicit MNodeIterator(MBasicBlock* block)
    1035         313 :       : last_(block->entryResumePoint() ? block->lastIns() : nullptr),
    1036         313 :         defIter_(block)
    1037             :     {
    1038         313 :         MOZ_ASSERT(bool(block->entryResumePoint()) == atResumePoint());
    1039             : 
    1040             :         // We use the last instruction to check for the entry resume point,
    1041             :         // assert that no control instruction has any resume point.  If so, then
    1042             :         // we need to handle this case in this iterator.
    1043         313 :         MOZ_ASSERT(!block->lastIns()->resumePoint());
    1044         313 :     }
    1045             : 
    1046        2716 :     MNodeIterator operator ++(int) {
    1047        2716 :         MNodeIterator old(*this);
    1048        2716 :         if (more())
    1049        2716 :             next();
    1050        2716 :         return old;
    1051             :     }
    1052             : 
    1053        3029 :     explicit operator bool() const {
    1054        3029 :         return more();
    1055             :     }
    1056             : 
    1057        2716 :     MNode* operator*() {
    1058        2716 :         return getNode();
    1059             :     }
    1060             : 
    1061             :     MNode* operator ->() {
    1062             :         return getNode();
    1063             :     }
    1064             : 
    1065             : };
    1066             : 
    1067             : } // namespace jit
    1068             : } // namespace js
    1069             : 
    1070             : #endif /* jit_MIRGraph_h */

Generated by: LCOV version 1.13