LCOV - code coverage report
Current view: top level - js/src/jit - MIRGraph.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 614 953 64.4 %
Date: 2017-07-14 16:53:18 Functions: 85 114 74.6 %
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             : #include "jit/MIRGraph.h"
       8             : 
       9             : #include "jit/BytecodeAnalysis.h"
      10             : #include "jit/Ion.h"
      11             : #include "jit/JitSpewer.h"
      12             : #include "jit/MIR.h"
      13             : #include "jit/MIRGenerator.h"
      14             : #include "wasm/WasmTypes.h"
      15             : 
      16             : using namespace js;
      17             : using namespace js::jit;
      18             : using mozilla::Swap;
      19             : 
      20         179 : MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOptions& options,
      21             :                            TempAllocator* alloc, MIRGraph* graph, const CompileInfo* info,
      22         179 :                            const OptimizationInfo* optimizationInfo)
      23             :   : compartment(compartment),
      24             :     info_(info),
      25             :     optimizationInfo_(optimizationInfo),
      26             :     alloc_(alloc),
      27             :     graph_(graph),
      28         179 :     offThreadStatus_(Ok()),
      29         179 :     abortedPreliminaryGroups_(*alloc_),
      30             :     pauseBuild_(nullptr),
      31             :     cancelBuild_(false),
      32             :     wasmMaxStackArgBytes_(0),
      33             :     needsOverrecursedCheck_(false),
      34             :     needsStaticStackAlignment_(false),
      35             :     usesSimd_(false),
      36             :     cachedUsesSimd_(false),
      37             :     modifiesFrameArguments_(false),
      38             :     instrumentedProfiling_(false),
      39             :     instrumentedProfilingIsCached_(false),
      40             :     safeForMinorGC_(true),
      41             :     minWasmHeapLength_(0),
      42             :     options(options),
      43         358 :     gs_(alloc)
      44         179 : { }
      45             : 
      46             : bool
      47           0 : MIRGenerator::usesSimd()
      48             : {
      49           0 :     if (cachedUsesSimd_)
      50           0 :         return usesSimd_;
      51             : 
      52           0 :     cachedUsesSimd_ = true;
      53           0 :     for (ReversePostorderIterator block = graph_->rpoBegin(),
      54           0 :                                   end   = graph_->rpoEnd();
      55             :          block != end;
      56             :          block++)
      57             :     {
      58             :         // It's fine to use MInstructionIterator here because we don't have to
      59             :         // worry about Phis, since any reachable phi (or phi cycle) will have at
      60             :         // least one instruction as an input.
      61           0 :         for (MInstructionIterator inst = block->begin(); inst != block->end(); inst++) {
      62             :             // Instructions that have SIMD inputs but not a SIMD type are fine
      63             :             // to ignore, as their inputs are also reached at some point. By
      64             :             // induction, at least one instruction with a SIMD type is reached
      65             :             // at some point.
      66           0 :             if (IsSimdType(inst->type())) {
      67             :                 MOZ_ASSERT(SupportsSimd);
      68           0 :                 usesSimd_ = true;
      69           0 :                 return true;
      70             :             }
      71             :         }
      72             :     }
      73           0 :     usesSimd_ = false;
      74           0 :     return false;
      75             : }
      76             : 
      77             : mozilla::GenericErrorResult<AbortReason>
      78           2 : MIRGenerator::abort(AbortReason r)
      79             : {
      80           2 :     if (JitSpewEnabled(JitSpew_IonAbort)) {
      81           0 :         switch (r) {
      82             :           case AbortReason::Alloc:
      83           0 :             JitSpew(JitSpew_IonAbort, "AbortReason::Alloc");
      84           0 :             break;
      85             :           case AbortReason::Inlining:
      86           0 :             JitSpew(JitSpew_IonAbort, "AbortReason::Inlining");
      87           0 :             break;
      88             :           case AbortReason::PreliminaryObjects:
      89           0 :             JitSpew(JitSpew_IonAbort, "AbortReason::PreliminaryObjects");
      90           0 :             break;
      91             :           case AbortReason::Disable:
      92           0 :             JitSpew(JitSpew_IonAbort, "AbortReason::Disable");
      93           0 :             break;
      94             :           case AbortReason::Error:
      95           0 :             JitSpew(JitSpew_IonAbort, "AbortReason::Error");
      96           0 :             break;
      97             :           case AbortReason::NoAbort:
      98           0 :             MOZ_CRASH("Abort with AbortReason::NoAbort");
      99             :             break;
     100             :         }
     101             :     }
     102           2 :     return Err(mozilla::Move(r));
     103             : }
     104             : 
     105             : mozilla::GenericErrorResult<AbortReason>
     106           3 : MIRGenerator::abortFmt(AbortReason r, const char* message, va_list ap)
     107             : {
     108           3 :     JitSpewVA(JitSpew_IonAbort, message, ap);
     109           3 :     return Err(mozilla::Move(r));
     110             : }
     111             : 
     112             : mozilla::GenericErrorResult<AbortReason>
     113           0 : MIRGenerator::abort(AbortReason r, const char* message, ...)
     114             : {
     115             :     va_list ap;
     116           0 :     va_start(ap, message);
     117           0 :     auto forward = abortFmt(r, message, ap);
     118           0 :     va_end(ap);
     119           0 :     return forward;
     120             : }
     121             : 
     122             : void
     123          13 : MIRGenerator::addAbortedPreliminaryGroup(ObjectGroup* group)
     124             : {
     125          13 :     for (size_t i = 0; i < abortedPreliminaryGroups_.length(); i++) {
     126           8 :         if (group == abortedPreliminaryGroups_[i])
     127          16 :             return;
     128             :     }
     129          10 :     AutoEnterOOMUnsafeRegion oomUnsafe;
     130           5 :     if (!abortedPreliminaryGroups_.append(group))
     131           0 :         oomUnsafe.crash("addAbortedPreliminaryGroup");
     132             : }
     133             : 
     134             : void
     135        4879 : MIRGraph::addBlock(MBasicBlock* block)
     136             : {
     137        4879 :     MOZ_ASSERT(block);
     138        4879 :     block->setId(blockIdGen_++);
     139        4879 :     blocks_.pushBack(block);
     140        4879 :     numBlocks_++;
     141        4879 : }
     142             : 
     143             : void
     144          18 : MIRGraph::insertBlockAfter(MBasicBlock* at, MBasicBlock* block)
     145             : {
     146          18 :     block->setId(blockIdGen_++);
     147          18 :     blocks_.insertAfter(at, block);
     148          18 :     numBlocks_++;
     149          18 : }
     150             : 
     151             : void
     152           0 : MIRGraph::insertBlockBefore(MBasicBlock* at, MBasicBlock* block)
     153             : {
     154           0 :     block->setId(blockIdGen_++);
     155           0 :     blocks_.insertBefore(at, block);
     156           0 :     numBlocks_++;
     157           0 : }
     158             : 
     159             : void
     160           0 : MIRGraph::renumberBlocksAfter(MBasicBlock* at)
     161             : {
     162           0 :     MBasicBlockIterator iter = begin(at);
     163           0 :     iter++;
     164             : 
     165           0 :     uint32_t id = at->id();
     166           0 :     for (; iter != end(); iter++)
     167           0 :         iter->setId(++id);
     168           0 : }
     169             : 
     170             : bool
     171           1 : MIRGraph::removeSuccessorBlocks(MBasicBlock* start)
     172             : {
     173           1 :     if (!start->hasLastIns())
     174           0 :         return true;
     175             : 
     176           1 :     start->mark();
     177             : 
     178             :     // Mark all successors.
     179           2 :     Vector<MBasicBlock*, 4, SystemAllocPolicy> blocks;
     180           3 :     for (size_t i = 0; i < start->numSuccessors(); i++) {
     181           2 :         if (start->getSuccessor(i)->isMarked())
     182           0 :             continue;
     183           2 :         if (!blocks.append(start->getSuccessor(i)))
     184           0 :             return false;
     185           2 :         start->getSuccessor(i)->mark();
     186             :     }
     187         138 :     for (size_t i = 0; i < blocks.length(); i++) {
     188         137 :         MBasicBlock* block = blocks[i];
     189         137 :         if (!block->hasLastIns())
     190           2 :             continue;
     191             : 
     192         305 :         for (size_t j = 0; j < block->numSuccessors(); j++) {
     193         170 :             if (block->getSuccessor(j)->isMarked())
     194          35 :                 continue;
     195         135 :             if (!blocks.append(block->getSuccessor(j)))
     196           0 :                 return false;
     197         135 :             block->getSuccessor(j)->mark();
     198             :         }
     199             :     }
     200             : 
     201           1 :     if (osrBlock()) {
     202           0 :         if (osrBlock()->getSuccessor(0)->isMarked())
     203           0 :             osrBlock()->mark();
     204             :     }
     205             : 
     206             :     // Remove blocks.
     207             :     // If they don't have any predecessor
     208         138 :     for (size_t i = 0; i < blocks.length(); i++) {
     209         137 :         MBasicBlock* block = blocks[i];
     210         137 :         bool allMarked = true;
     211         308 :         for (size_t i = 0; i < block->numPredecessors(); i++) {
     212         171 :             if (block->getPredecessor(i)->isMarked())
     213         171 :                 continue;
     214           0 :             allMarked = false;
     215           0 :             break;
     216             :         }
     217         137 :         if (allMarked) {
     218         137 :             removeBlock(block);
     219             :         } else {
     220           0 :             MOZ_ASSERT(block != osrBlock());
     221           0 :             for (size_t j = 0; j < block->numPredecessors(); ) {
     222           0 :                 if (!block->getPredecessor(j)->isMarked()) {
     223           0 :                     j++;
     224           0 :                     continue;
     225             :                 }
     226           0 :                 block->removePredecessor(block->getPredecessor(j));
     227             :             }
     228             :             // This shouldn't have any instructions yet.
     229           0 :             MOZ_ASSERT(block->begin() == block->end());
     230             :         }
     231             :     }
     232             : 
     233           1 :     if (osrBlock()) {
     234           0 :         if (osrBlock()->getSuccessor(0)->isDead())
     235           0 :             removeBlock(osrBlock());
     236             :     }
     237             : 
     238         138 :     for (size_t i = 0; i < blocks.length(); i++)
     239         137 :         blocks[i]->unmark();
     240           1 :     start->unmark();
     241             : 
     242           1 :     return true;
     243             : }
     244             : 
     245             : void
     246         392 : MIRGraph::removeBlock(MBasicBlock* block)
     247             : {
     248             :     // Remove a block from the graph. It will also cleanup the block.
     249             : 
     250         392 :     if (block == osrBlock_)
     251           0 :         osrBlock_ = nullptr;
     252             : 
     253         392 :     if (returnAccumulator_) {
     254           0 :         size_t i = 0;
     255           0 :         while (i < returnAccumulator_->length()) {
     256           0 :             if ((*returnAccumulator_)[i] == block)
     257           0 :                 returnAccumulator_->erase(returnAccumulator_->begin() + i);
     258             :             else
     259           0 :                 i++;
     260             :         }
     261             :     }
     262             : 
     263         392 :     block->clear();
     264         392 :     block->markAsDead();
     265             : 
     266         392 :     if (block->isInList()) {
     267         390 :         blocks_.remove(block);
     268         390 :         numBlocks_--;
     269             :     }
     270         392 : }
     271             : 
     272             : void
     273           0 : MIRGraph::removeBlockIncludingPhis(MBasicBlock* block)
     274             : {
     275             :     // removeBlock doesn't clear phis because of IonBuilder constraints. Here,
     276             :     // we want to totally clear everything.
     277           0 :     removeBlock(block);
     278           0 :     block->discardAllPhis();
     279           0 : }
     280             : 
     281             : void
     282         214 : MIRGraph::unmarkBlocks()
     283             : {
     284       11571 :     for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++)
     285       11357 :         i->unmark();
     286         214 : }
     287             : 
     288             : MBasicBlock*
     289        3828 : MBasicBlock::New(MIRGraph& graph, BytecodeAnalysis* analysis, const CompileInfo& info,
     290             :                  MBasicBlock* pred, BytecodeSite* site, Kind kind)
     291             : {
     292        3828 :     MOZ_ASSERT(site->pc() != nullptr);
     293             : 
     294        3828 :     MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
     295        3828 :     if (!block->init())
     296           0 :         return nullptr;
     297             : 
     298        3828 :     if (!block->inherit(graph.alloc(), analysis, pred, 0))
     299           0 :         return nullptr;
     300             : 
     301        3828 :     return block;
     302             : }
     303             : 
     304             : MBasicBlock*
     305           0 : MBasicBlock::NewPopN(MIRGraph& graph, const CompileInfo& info,
     306             :                      MBasicBlock* pred, BytecodeSite* site, Kind kind, uint32_t popped)
     307             : {
     308           0 :     MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
     309           0 :     if (!block->init())
     310           0 :         return nullptr;
     311             : 
     312           0 :     if (!block->inherit(graph.alloc(), nullptr, pred, popped))
     313           0 :         return nullptr;
     314             : 
     315           0 :     return block;
     316             : }
     317             : 
     318             : MBasicBlock*
     319           0 : MBasicBlock::NewWithResumePoint(MIRGraph& graph, const CompileInfo& info,
     320             :                                 MBasicBlock* pred, BytecodeSite* site,
     321             :                                 MResumePoint* resumePoint)
     322             : {
     323           0 :     MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, NORMAL);
     324             : 
     325           0 :     MOZ_ASSERT(!resumePoint->instruction());
     326           0 :     resumePoint->block()->discardResumePoint(resumePoint, RefType_None);
     327           0 :     resumePoint->block_ = block;
     328           0 :     block->addResumePoint(resumePoint);
     329           0 :     block->entryResumePoint_ = resumePoint;
     330             : 
     331           0 :     if (!block->init())
     332           0 :         return nullptr;
     333             : 
     334           0 :     if (!block->inheritResumePoint(pred))
     335           0 :         return nullptr;
     336             : 
     337           0 :     return block;
     338             : }
     339             : 
     340             : MBasicBlock*
     341         118 : MBasicBlock::NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info,
     342             :                                   MBasicBlock* pred, BytecodeSite* site,
     343             :                                   unsigned stackPhiCount)
     344             : {
     345         118 :     MOZ_ASSERT(site->pc() != nullptr);
     346             : 
     347         118 :     MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, PENDING_LOOP_HEADER);
     348         118 :     if (!block->init())
     349           0 :         return nullptr;
     350             : 
     351         118 :     if (!block->inherit(graph.alloc(), nullptr, pred, 0, stackPhiCount))
     352           0 :         return nullptr;
     353             : 
     354         118 :     return block;
     355             : }
     356             : 
     357             : MBasicBlock*
     358          14 : MBasicBlock::NewSplitEdge(MIRGraph& graph, MBasicBlock* pred, size_t predEdgeIdx, MBasicBlock* succ)
     359             : {
     360          14 :     MBasicBlock* split = nullptr;
     361          14 :     if (!succ->pc()) {
     362             :         // The predecessor does not have a PC, this is a Wasm compilation.
     363           0 :         split = MBasicBlock::New(graph, succ->info(), pred, SPLIT_EDGE);
     364           0 :         if (!split)
     365           0 :             return nullptr;
     366             :     } else {
     367             :         // The predecessor has a PC, this is an IonBuilder compilation.
     368          14 :         MResumePoint* succEntry = succ->entryResumePoint();
     369             : 
     370          14 :         BytecodeSite* site = new(graph.alloc()) BytecodeSite(succ->trackedTree(), succEntry->pc());
     371          14 :         split = new(graph.alloc()) MBasicBlock(graph, succ->info(), site, SPLIT_EDGE);
     372             : 
     373          14 :         if (!split->init())
     374           0 :             return nullptr;
     375             : 
     376             :         // A split edge is used to simplify the graph to avoid having a
     377             :         // predecessor with multiple successors as well as a successor with
     378             :         // multiple predecessors.  As instructions can be moved in this
     379             :         // split-edge block, we need to give this block a resume point. To do
     380             :         // so, we copy the entry resume points of the successor and filter the
     381             :         // phis to keep inputs from the current edge.
     382             : 
     383             :         // Propagate the caller resume point from the inherited block.
     384          14 :         split->callerResumePoint_ = succ->callerResumePoint();
     385             : 
     386             :         // Split-edge are created after the interpreter stack emulation. Thus,
     387             :         // there is no need for creating slots.
     388          14 :         split->stackPosition_ = succEntry->stackDepth();
     389             : 
     390             :         // Create a resume point using our initial stack position.
     391          14 :         MResumePoint* splitEntry = new(graph.alloc()) MResumePoint(split, succEntry->pc(),
     392          14 :                                                                    MResumePoint::ResumeAt);
     393          14 :         if (!splitEntry->init(graph.alloc()))
     394           0 :             return nullptr;
     395          14 :         split->entryResumePoint_ = splitEntry;
     396             : 
     397             :         // The target entry resume point might have phi operands, keep the
     398             :         // operands of the phi coming from our edge.
     399          14 :         size_t succEdgeIdx = succ->indexForPredecessor(pred);
     400             : 
     401         254 :         for (size_t i = 0, e = splitEntry->numOperands(); i < e; i++) {
     402         240 :             MDefinition* def = succEntry->getOperand(i);
     403             :             // This early in the pipeline, we have no recover instructions in
     404             :             // any entry resume point.
     405         240 :             MOZ_ASSERT_IF(def->block() == succ, def->isPhi());
     406         240 :             if (def->block() == succ)
     407           3 :                 def = def->toPhi()->getOperand(succEdgeIdx);
     408             : 
     409         240 :             splitEntry->initOperand(i, def);
     410             :         }
     411             : 
     412             :         // This is done in the New variant for wasm, so we cannot keep this
     413             :         // line below, where the rest of the graph is modified.
     414          14 :         if (!split->predecessors_.append(pred))
     415           0 :             return nullptr;
     416             :     }
     417             : 
     418          14 :     split->setLoopDepth(succ->loopDepth());
     419             : 
     420             :     // Insert the split edge block in-between.
     421          14 :     split->end(MGoto::New(graph.alloc(), succ));
     422             : 
     423          14 :     graph.insertBlockAfter(pred, split);
     424             : 
     425          14 :     pred->replaceSuccessor(predEdgeIdx, split);
     426          14 :     succ->replacePredecessor(pred, split);
     427          14 :     return split;
     428             : }
     429             : 
     430             : MBasicBlock*
     431           0 : MBasicBlock::New(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, Kind kind)
     432             : {
     433           0 :     BytecodeSite* site = new(graph.alloc()) BytecodeSite();
     434           0 :     MBasicBlock* block = new(graph.alloc()) MBasicBlock(graph, info, site, kind);
     435           0 :     if (!block->init())
     436           0 :         return nullptr;
     437             : 
     438           0 :     if (pred) {
     439           0 :         block->stackPosition_ = pred->stackPosition_;
     440             : 
     441           0 :         if (block->kind_ == PENDING_LOOP_HEADER) {
     442           0 :             size_t nphis = block->stackPosition_;
     443             : 
     444           0 :             size_t nfree = graph.phiFreeListLength();
     445             : 
     446           0 :             TempAllocator& alloc = graph.alloc();
     447           0 :             MPhi* phis = nullptr;
     448           0 :             if (nphis > nfree) {
     449           0 :                 phis = alloc.allocateArray<MPhi>(nphis - nfree);
     450           0 :                 if (!phis)
     451           0 :                     return nullptr;
     452             :             }
     453             : 
     454             :             // Note: Phis are inserted in the same order as the slots.
     455           0 :             for (size_t i = 0; i < nphis; i++) {
     456           0 :                 MDefinition* predSlot = pred->getSlot(i);
     457             : 
     458           0 :                 MOZ_ASSERT(predSlot->type() != MIRType::Value);
     459             : 
     460             :                 MPhi* phi;
     461           0 :                 if (i < nfree)
     462           0 :                     phi = graph.takePhiFromFreeList();
     463             :                 else
     464           0 :                     phi = phis + (i - nfree);
     465           0 :                 new(phi) MPhi(alloc, predSlot->type());
     466             : 
     467           0 :                 phi->addInlineInput(predSlot);
     468             : 
     469             :                 // Add append Phis in the block.
     470           0 :                 block->addPhi(phi);
     471           0 :                 block->setSlot(i, phi);
     472             :             }
     473             :         } else {
     474           0 :             block->copySlots(pred);
     475             :         }
     476             : 
     477           0 :         if (!block->predecessors_.append(pred))
     478           0 :             return nullptr;
     479             :     }
     480             : 
     481           0 :     return block;
     482             : }
     483             : 
     484        3960 : MBasicBlock::MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind)
     485             :   : unreachable_(false),
     486             :     specialized_(false),
     487             :     graph_(graph),
     488             :     info_(info),
     489             :     predecessors_(graph.alloc()),
     490        3960 :     stackPosition_(info_.firstStackSlot()),
     491             :     numDominated_(0),
     492        3960 :     pc_(site->pc()),
     493             :     lir_(nullptr),
     494             :     callerResumePoint_(nullptr),
     495             :     entryResumePoint_(nullptr),
     496             :     outerResumePoint_(nullptr),
     497             :     successorWithPhis_(nullptr),
     498             :     positionInPhiSuccessor_(0),
     499             :     loopDepth_(0),
     500             :     kind_(kind),
     501             :     mark_(false),
     502             :     immediatelyDominated_(graph.alloc()),
     503             :     immediateDominator_(nullptr),
     504             :     trackedSite_(site),
     505             :     hitCount_(0),
     506       11880 :     hitState_(HitState::NotDefined)
     507             : #if defined (JS_ION_PERF)
     508             :     , lineno_(0u),
     509             :     columnIndex_(0u)
     510             : #endif
     511             : {
     512        3960 : }
     513             : 
     514             : bool
     515        3960 : MBasicBlock::init()
     516             : {
     517        3960 :     return slots_.init(graph_.alloc(), info_.nslots());
     518             : }
     519             : 
     520             : bool
     521           0 : MBasicBlock::increaseSlots(size_t num)
     522             : {
     523           0 :     return slots_.growBy(graph_.alloc(), num);
     524             : }
     525             : 
     526             : bool
     527           0 : MBasicBlock::ensureHasSlots(size_t num)
     528             : {
     529           0 :     size_t depth = stackDepth() + num;
     530           0 :     if (depth > nslots()) {
     531           0 :         if (!increaseSlots(depth - nslots()))
     532           0 :             return false;
     533             :     }
     534           0 :     return true;
     535             : }
     536             : 
     537             : void
     538        3645 : MBasicBlock::copySlots(MBasicBlock* from)
     539             : {
     540        3645 :     MOZ_ASSERT(stackPosition_ <= from->stackPosition_);
     541             : 
     542        3645 :     MDefinition** thisSlots = slots_.begin();
     543        3645 :     MDefinition** fromSlots = from->slots_.begin();
     544       49807 :     for (size_t i = 0, e = stackPosition_; i < e; ++i)
     545       46162 :         thisSlots[i] = fromSlots[i];
     546        3645 : }
     547             : 
     548             : bool
     549        3946 : MBasicBlock::inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred,
     550             :                      uint32_t popped, unsigned stackPhiCount)
     551             : {
     552        3946 :     if (pred) {
     553        3729 :         stackPosition_ = pred->stackPosition_;
     554        3729 :         MOZ_ASSERT(stackPosition_ >= popped);
     555        3729 :         stackPosition_ -= popped;
     556        3729 :         if (kind_ != PENDING_LOOP_HEADER)
     557        3611 :             copySlots(pred);
     558             :     } else {
     559         217 :         uint32_t stackDepth = analysis->info(pc()).stackDepth;
     560         217 :         stackPosition_ = info().firstStackSlot() + stackDepth;
     561         217 :         MOZ_ASSERT(stackPosition_ >= popped);
     562         217 :         stackPosition_ -= popped;
     563             :     }
     564             : 
     565        3946 :     MOZ_ASSERT(info_.nslots() >= stackPosition_);
     566        3946 :     MOZ_ASSERT(!entryResumePoint_);
     567             : 
     568             :     // Propagate the caller resume point from the inherited block.
     569        3946 :     callerResumePoint_ = pred ? pred->callerResumePoint() : nullptr;
     570             : 
     571             :     // Create a resume point using our initial stack state.
     572        3946 :     entryResumePoint_ = new(alloc) MResumePoint(this, pc(), MResumePoint::ResumeAt);
     573        3946 :     if (!entryResumePoint_->init(alloc))
     574           0 :         return false;
     575             : 
     576        3946 :     if (pred) {
     577        3729 :         if (!predecessors_.append(pred))
     578           0 :             return false;
     579             : 
     580        3729 :         if (kind_ == PENDING_LOOP_HEADER) {
     581         118 :             size_t i = 0;
     582        1647 :             for (i = 0; i < info().firstStackSlot(); i++) {
     583        1529 :                 MPhi* phi = MPhi::New(alloc.fallible());
     584        1529 :                 if (!phi)
     585           0 :                     return false;
     586        1529 :                 phi->addInlineInput(pred->getSlot(i));
     587        1529 :                 addPhi(phi);
     588        1529 :                 setSlot(i, phi);
     589        1529 :                 entryResumePoint()->initOperand(i, phi);
     590             :             }
     591             : 
     592         118 :             MOZ_ASSERT(stackPhiCount <= stackDepth());
     593         118 :             MOZ_ASSERT(info().firstStackSlot() <= stackDepth() - stackPhiCount);
     594             : 
     595             :             // Avoid creating new phis for stack values that aren't part of the
     596             :             // loop.  Note that for loop headers that can OSR, all values on the
     597             :             // stack are part of the loop.
     598         118 :             for (; i < stackDepth() - stackPhiCount; i++) {
     599           0 :                 MDefinition* val = pred->getSlot(i);
     600           0 :                 setSlot(i, val);
     601           0 :                 entryResumePoint()->initOperand(i, val);
     602             :             }
     603             : 
     604         130 :             for (; i < stackDepth(); i++) {
     605           6 :                 MPhi* phi = MPhi::New(alloc.fallible());
     606           6 :                 if (!phi)
     607           0 :                     return false;
     608           6 :                 phi->addInlineInput(pred->getSlot(i));
     609           6 :                 addPhi(phi);
     610           6 :                 setSlot(i, phi);
     611           6 :                 entryResumePoint()->initOperand(i, phi);
     612             :             }
     613             :         } else {
     614       49275 :             for (size_t i = 0; i < stackDepth(); i++)
     615       45664 :                 entryResumePoint()->initOperand(i, getSlot(i));
     616             :         }
     617             :     } else {
     618             :         /*
     619             :          * Don't leave the operands uninitialized for the caller, as it may not
     620             :          * initialize them later on.
     621             :          */
     622        2571 :         for (size_t i = 0; i < stackDepth(); i++)
     623        2354 :             entryResumePoint()->clearOperand(i);
     624             :     }
     625             : 
     626        3946 :     return true;
     627             : }
     628             : 
     629             : bool
     630           0 : MBasicBlock::inheritResumePoint(MBasicBlock* pred)
     631             : {
     632             :     // Copy slots from the resume point.
     633           0 :     stackPosition_ = entryResumePoint_->stackDepth();
     634           0 :     for (uint32_t i = 0; i < stackPosition_; i++)
     635           0 :         slots_[i] = entryResumePoint_->getOperand(i);
     636             : 
     637           0 :     MOZ_ASSERT(info_.nslots() >= stackPosition_);
     638           0 :     MOZ_ASSERT(kind_ != PENDING_LOOP_HEADER);
     639           0 :     MOZ_ASSERT(pred != nullptr);
     640             : 
     641           0 :     callerResumePoint_ = pred->callerResumePoint();
     642             : 
     643           0 :     if (!predecessors_.append(pred))
     644           0 :         return false;
     645             : 
     646           0 :     return true;
     647             : }
     648             : 
     649             : void
     650          34 : MBasicBlock::inheritSlots(MBasicBlock* parent)
     651             : {
     652          34 :     stackPosition_ = parent->stackPosition_;
     653          34 :     copySlots(parent);
     654          34 : }
     655             : 
     656             : bool
     657          34 : MBasicBlock::initEntrySlots(TempAllocator& alloc)
     658             : {
     659             :     // Remove the previous resume point.
     660          34 :     discardResumePoint(entryResumePoint_);
     661             : 
     662             :     // Create a resume point using our initial stack state.
     663          34 :     entryResumePoint_ = MResumePoint::New(alloc, this, pc(), MResumePoint::ResumeAt);
     664          34 :     if (!entryResumePoint_)
     665           0 :         return false;
     666          34 :     return true;
     667             : }
     668             : 
     669             : MDefinition*
     670      155031 : MBasicBlock::getSlot(uint32_t index)
     671             : {
     672      155031 :     MOZ_ASSERT(index < stackPosition_);
     673      155031 :     return slots_[index];
     674             : }
     675             : 
     676             : void
     677        1872 : MBasicBlock::initSlot(uint32_t slot, MDefinition* ins)
     678             : {
     679        1872 :     slots_[slot] = ins;
     680        1872 :     if (entryResumePoint())
     681        1872 :         entryResumePoint()->initOperand(slot, ins);
     682        1872 : }
     683             : 
     684             : void
     685           0 : MBasicBlock::shimmySlots(int discardDepth)
     686             : {
     687             :     // Move all slots above the given depth down by one,
     688             :     // overwriting the MDefinition at discardDepth.
     689             : 
     690           0 :     MOZ_ASSERT(discardDepth < 0);
     691           0 :     MOZ_ASSERT(stackPosition_ + discardDepth >= info_.firstStackSlot());
     692             : 
     693           0 :     for (int i = discardDepth; i < -1; i++)
     694           0 :         slots_[stackPosition_ + i] = slots_[stackPosition_ + i + 1];
     695             : 
     696           0 :     --stackPosition_;
     697           0 : }
     698             : 
     699             : bool
     700           4 : MBasicBlock::linkOsrValues(MStart* start)
     701             : {
     702           4 :     MResumePoint* res = start->resumePoint();
     703             : 
     704          88 :     for (uint32_t i = 0; i < stackDepth(); i++) {
     705          84 :         MDefinition* def = slots_[i];
     706          84 :         MInstruction* cloneRp = nullptr;
     707          84 :         if (i == info().environmentChainSlot()) {
     708           4 :             if (def->isOsrEnvironmentChain())
     709           3 :                 cloneRp = def->toOsrEnvironmentChain();
     710          80 :         } else if (i == info().returnValueSlot()) {
     711           4 :             if (def->isOsrReturnValue())
     712           4 :                 cloneRp = def->toOsrReturnValue();
     713          76 :         } else if (info().hasArguments() && i == info().argsObjSlot()) {
     714           1 :             MOZ_ASSERT(def->isConstant() || def->isOsrArgumentsObject());
     715           1 :             MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined);
     716           1 :             if (def->isOsrArgumentsObject())
     717           0 :                 cloneRp = def->toOsrArgumentsObject();
     718             :         } else {
     719          75 :             MOZ_ASSERT(def->isOsrValue() || def->isGetArgumentsObjectArg() || def->isConstant() ||
     720             :                        def->isParameter());
     721             : 
     722             :             // A constant Undefined can show up here for an argument slot when
     723             :             // the function has an arguments object, but the argument in
     724             :             // question is stored on the scope chain.
     725          75 :             MOZ_ASSERT_IF(def->isConstant(), def->toConstant()->type() == MIRType::Undefined);
     726             : 
     727          75 :             if (def->isOsrValue())
     728          58 :                 cloneRp = def->toOsrValue();
     729          17 :             else if (def->isGetArgumentsObjectArg())
     730           0 :                 cloneRp = def->toGetArgumentsObjectArg();
     731          17 :             else if (def->isParameter())
     732          17 :                 cloneRp = def->toParameter();
     733             :         }
     734             : 
     735          84 :         if (cloneRp) {
     736          82 :             MResumePoint* clone = MResumePoint::Copy(graph().alloc(), res);
     737          82 :             if (!clone)
     738           0 :                 return false;
     739          82 :             cloneRp->setResumePoint(clone);
     740             :         }
     741             :     }
     742             : 
     743           4 :     return true;
     744             : }
     745             : 
     746             : void
     747        5918 : MBasicBlock::setSlot(uint32_t slot, MDefinition* ins)
     748             : {
     749        5918 :     slots_[slot] = ins;
     750        5918 : }
     751             : 
     752             : void
     753        1315 : MBasicBlock::setVariable(uint32_t index)
     754             : {
     755        1315 :     MOZ_ASSERT(stackPosition_ > info_.firstStackSlot());
     756        1315 :     setSlot(index, slots_[stackPosition_ - 1]);
     757        1315 : }
     758             : 
     759             : void
     760          18 : MBasicBlock::setArg(uint32_t arg)
     761             : {
     762          18 :     setVariable(info_.argSlot(arg));
     763          18 : }
     764             : 
     765             : void
     766        1297 : MBasicBlock::setLocal(uint32_t local)
     767             : {
     768        1297 :     setVariable(info_.localSlot(local));
     769        1297 : }
     770             : 
     771             : void
     772           0 : MBasicBlock::setSlot(uint32_t slot)
     773             : {
     774           0 :     setVariable(slot);
     775           0 : }
     776             : 
     777             : void
     778         111 : MBasicBlock::rewriteSlot(uint32_t slot, MDefinition* ins)
     779             : {
     780         111 :     setSlot(slot, ins);
     781         111 : }
     782             : 
     783             : void
     784           0 : MBasicBlock::rewriteAtDepth(int32_t depth, MDefinition* ins)
     785             : {
     786           0 :     MOZ_ASSERT(depth < 0);
     787           0 :     MOZ_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
     788           0 :     rewriteSlot(stackPosition_ + depth, ins);
     789           0 : }
     790             : 
     791             : void
     792       17241 : MBasicBlock::push(MDefinition* ins)
     793             : {
     794       17241 :     MOZ_ASSERT(stackPosition_ < nslots());
     795       17241 :     slots_[stackPosition_++] = ins;
     796       17241 : }
     797             : 
     798             : void
     799        4177 : MBasicBlock::pushVariable(uint32_t slot)
     800             : {
     801        4177 :     push(slots_[slot]);
     802        4177 : }
     803             : 
     804             : void
     805         380 : MBasicBlock::pushArg(uint32_t arg)
     806             : {
     807         380 :     pushVariable(info_.argSlot(arg));
     808         380 : }
     809             : 
     810             : void
     811        3418 : MBasicBlock::pushLocal(uint32_t local)
     812             : {
     813        3418 :     pushVariable(info_.localSlot(local));
     814        3418 : }
     815             : 
     816             : void
     817         379 : MBasicBlock::pushSlot(uint32_t slot)
     818             : {
     819         379 :     pushVariable(slot);
     820         379 : }
     821             : 
     822             : MDefinition*
     823       14599 : MBasicBlock::pop()
     824             : {
     825       14599 :     MOZ_ASSERT(stackPosition_ > info_.firstStackSlot());
     826       14599 :     return slots_[--stackPosition_];
     827             : }
     828             : 
     829             : void
     830        2271 : MBasicBlock::popn(uint32_t n)
     831             : {
     832        2271 :     MOZ_ASSERT(stackPosition_ - n >= info_.firstStackSlot());
     833        2271 :     MOZ_ASSERT(stackPosition_ >= stackPosition_ - n);
     834        2271 :     stackPosition_ -= n;
     835        2271 : }
     836             : 
     837             : MDefinition*
     838         175 : MBasicBlock::environmentChain()
     839             : {
     840         175 :     return getSlot(info().environmentChainSlot());
     841             : }
     842             : 
     843             : MDefinition*
     844         147 : MBasicBlock::argumentsObject()
     845             : {
     846         147 :     return getSlot(info().argsObjSlot());
     847             : }
     848             : 
     849             : void
     850         151 : MBasicBlock::setEnvironmentChain(MDefinition* scopeObj)
     851             : {
     852         151 :     setSlot(info().environmentChainSlot(), scopeObj);
     853         151 : }
     854             : 
     855             : void
     856         135 : MBasicBlock::setArgumentsObject(MDefinition* argsObj)
     857             : {
     858         135 :     setSlot(info().argsObjSlot(), argsObj);
     859         135 : }
     860             : 
     861             : void
     862           9 : MBasicBlock::pick(int32_t depth)
     863             : {
     864             :     // pick take an element and move it to the top.
     865             :     // pick(-2):
     866             :     //   A B C D E
     867             :     //   A B D C E [ swapAt(-2) ]
     868             :     //   A B D E C [ swapAt(-1) ]
     869          15 :     for (; depth < 0; depth++)
     870           6 :         swapAt(depth);
     871           3 : }
     872             : 
     873             : void
     874           6 : MBasicBlock::unpick(int32_t depth)
     875             : {
     876             :     // unpick take the top of the stack element and move it under the depth-th
     877             :     // element;
     878             :     // unpick(-2):
     879             :     //   A B C D E
     880             :     //   A B C E D [ swapAt(-1) ]
     881             :     //   A B E C D [ swapAt(-2) ]
     882          16 :     for (int32_t n = -1; n >= depth; n--)
     883          10 :         swapAt(n);
     884           6 : }
     885             : 
     886             : void
     887          87 : MBasicBlock::swapAt(int32_t depth)
     888             : {
     889          87 :     uint32_t lhsDepth = stackPosition_ + depth - 1;
     890          87 :     uint32_t rhsDepth = stackPosition_ + depth;
     891             : 
     892          87 :     MDefinition* temp = slots_[lhsDepth];
     893          87 :     slots_[lhsDepth] = slots_[rhsDepth];
     894          87 :     slots_[rhsDepth] = temp;
     895          87 : }
     896             : 
     897             : MDefinition*
     898       21973 : MBasicBlock::peek(int32_t depth)
     899             : {
     900       21973 :     MOZ_ASSERT(depth < 0);
     901       21973 :     MOZ_ASSERT(stackPosition_ + depth >= info_.firstStackSlot());
     902       21973 :     return getSlot(stackPosition_ + depth);
     903             : }
     904             : 
     905             : void
     906          86 : MBasicBlock::discardLastIns()
     907             : {
     908          86 :     discard(lastIns());
     909          86 : }
     910             : 
     911             : MConstant*
     912        4464 : MBasicBlock::optimizedOutConstant(TempAllocator& alloc)
     913             : {
     914             :     // If the first instruction is a MConstant(MagicValue(JS_OPTIMIZED_OUT))
     915             :     // then reuse it.
     916        4464 :     MInstruction* ins = *begin();
     917        4464 :     if (ins->type() == MIRType::MagicOptimizedOut)
     918        3656 :         return ins->toConstant();
     919             : 
     920         808 :     MConstant* constant = MConstant::New(alloc, MagicValue(JS_OPTIMIZED_OUT));
     921         808 :     insertBefore(ins, constant);
     922         808 :     return constant;
     923             : }
     924             : 
     925             : void
     926           0 : MBasicBlock::addFromElsewhere(MInstruction* ins)
     927             : {
     928           0 :     MOZ_ASSERT(ins->block() != this);
     929             : 
     930             :     // Remove |ins| from its containing block.
     931           0 :     ins->block()->instructions_.remove(ins);
     932             : 
     933             :     // Add it to this block.
     934           0 :     add(ins);
     935           0 : }
     936             : 
     937             : void
     938          35 : MBasicBlock::moveBefore(MInstruction* at, MInstruction* ins)
     939             : {
     940             :     // Remove |ins| from the current block.
     941          35 :     MOZ_ASSERT(ins->block() == this);
     942          35 :     instructions_.remove(ins);
     943             : 
     944             :     // Insert into new block, which may be distinct.
     945             :     // Uses and operands are untouched.
     946          35 :     ins->setBlock(at->block());
     947          35 :     at->block()->instructions_.insertBefore(at, ins);
     948          35 :     ins->setTrackedSite(at->trackedSite());
     949          35 : }
     950             : 
     951             : MInstruction*
     952       14913 : MBasicBlock::safeInsertTop(MDefinition* ins, IgnoreTop ignore)
     953             : {
     954       14913 :     MOZ_ASSERT(graph().osrBlock() != this,
     955             :                "We are not supposed to add any instruction in OSR blocks.");
     956             : 
     957             :     // Beta nodes and interrupt checks are required to be located at the
     958             :     // beginnings of basic blocks, so we must insert new instructions after any
     959             :     // such instructions.
     960           0 :     MInstructionIterator insertIter = !ins || ins->isPhi()
     961       14913 :                                     ? begin()
     962       14913 :                                     : begin(ins->toInstruction());
     963       87271 :     while (insertIter->isBeta() ||
     964       50771 :            insertIter->isInterruptCheck() ||
     965       42016 :            insertIter->isConstant() ||
     966       68874 :            insertIter->isParameter() ||
     967       31858 :            (!(ignore & IgnoreRecover) && insertIter->isRecoveredOnBailout()))
     968             :     {
     969       10658 :         insertIter++;
     970             :     }
     971             : 
     972       14913 :     return *insertIter;
     973             : }
     974             : 
     975             : void
     976         811 : MBasicBlock::discardResumePoint(MResumePoint* rp, ReferencesType refType /* = RefType_Default */)
     977             : {
     978         811 :     if (refType & RefType_DiscardOperands)
     979         811 :         rp->releaseUses();
     980             : #ifdef DEBUG
     981         811 :     MResumePointIterator iter = resumePointsBegin();
     982        1605 :     while (*iter != rp) {
     983             :         // We should reach it before reaching the end.
     984         397 :         MOZ_ASSERT(iter != resumePointsEnd());
     985         397 :         iter++;
     986             :     }
     987         811 :     resumePoints_.removeAt(iter);
     988             : #endif
     989         811 : }
     990             : 
     991             : void
     992        2549 : MBasicBlock::prepareForDiscard(MInstruction* ins, ReferencesType refType /* = RefType_Default */)
     993             : {
     994             :     // Only remove instructions from the same basic block.  This is needed for
     995             :     // correctly removing the resume point if any.
     996        2549 :     MOZ_ASSERT(ins->block() == this);
     997             : 
     998        2549 :     MResumePoint* rp = ins->resumePoint();
     999        2549 :     if ((refType & RefType_DiscardResumePoint) && rp)
    1000         327 :         discardResumePoint(rp, refType);
    1001             : 
    1002             :     // We need to assert that instructions have no uses after removing the their
    1003             :     // resume points operands as they could be captured by their own resume
    1004             :     // point.
    1005        2549 :     MOZ_ASSERT_IF(refType & RefType_AssertNoUses, !ins->hasUses());
    1006             : 
    1007        2549 :     const uint32_t InstructionOperands = RefType_DiscardOperands | RefType_DiscardInstruction;
    1008        2549 :     if ((refType & InstructionOperands) == InstructionOperands) {
    1009        2362 :         for (size_t i = 0, e = ins->numOperands(); i < e; i++)
    1010         880 :             ins->releaseOperand(i);
    1011             :     }
    1012             : 
    1013        2549 :     ins->setDiscarded();
    1014        2549 : }
    1015             : 
    1016             : void
    1017         248 : MBasicBlock::discard(MInstruction* ins)
    1018             : {
    1019         248 :     prepareForDiscard(ins);
    1020         248 :     instructions_.remove(ins);
    1021         248 : }
    1022             : 
    1023             : void
    1024        1067 : MBasicBlock::discardIgnoreOperands(MInstruction* ins)
    1025             : {
    1026             : #ifdef DEBUG
    1027        1397 :     for (size_t i = 0, e = ins->numOperands(); i < e; i++)
    1028         330 :         MOZ_ASSERT(!ins->hasOperand(i));
    1029             : #endif
    1030             : 
    1031        1067 :     prepareForDiscard(ins, RefType_IgnoreOperands);
    1032        1067 :     instructions_.remove(ins);
    1033        1067 : }
    1034             : 
    1035             : void
    1036          50 : MBasicBlock::discardDef(MDefinition* at)
    1037             : {
    1038          50 :     if (at->isPhi())
    1039           0 :         at->block_->discardPhi(at->toPhi());
    1040             :     else
    1041          50 :         at->block_->discard(at->toInstruction());
    1042          50 : }
    1043             : 
    1044             : void
    1045         393 : MBasicBlock::discardAllInstructions()
    1046             : {
    1047         393 :     MInstructionIterator iter = begin();
    1048         393 :     discardAllInstructionsStartingAt(iter);
    1049         393 : }
    1050             : 
    1051             : void
    1052        1662 : MBasicBlock::discardAllInstructionsStartingAt(MInstructionIterator iter)
    1053             : {
    1054        2896 :     while (iter != end()) {
    1055             :         // Discard operands and resume point operands and flag the instruction
    1056             :         // as discarded.  Also we do not assert that we have no uses as blocks
    1057             :         // might be removed in reverse post order.
    1058        1234 :         MInstruction* ins = *iter++;
    1059        1234 :         prepareForDiscard(ins, RefType_DefaultNoAssert);
    1060        1234 :         instructions_.remove(ins);
    1061             :     }
    1062         428 : }
    1063             : 
    1064             : void
    1065         392 : MBasicBlock::discardAllPhiOperands()
    1066             : {
    1067         431 :     for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++)
    1068          39 :         iter->removeAllOperands();
    1069             : 
    1070         773 :     for (MBasicBlock** pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
    1071         381 :         (*pred)->clearSuccessorWithPhis();
    1072         392 : }
    1073             : 
    1074             : void
    1075           0 : MBasicBlock::discardAllPhis()
    1076             : {
    1077           0 :     discardAllPhiOperands();
    1078           0 :     phis_.clear();
    1079           0 : }
    1080             : 
    1081             : void
    1082         393 : MBasicBlock::discardAllResumePoints(bool discardEntry)
    1083             : {
    1084         393 :     if (outerResumePoint_)
    1085           9 :         clearOuterResumePoint();
    1086             : 
    1087         393 :     if (discardEntry && entryResumePoint_)
    1088         392 :         clearEntryResumePoint();
    1089             : 
    1090             : #ifdef DEBUG
    1091         393 :     if (!entryResumePoint()) {
    1092         392 :         MOZ_ASSERT(resumePointsEmpty());
    1093             :     } else {
    1094           1 :         MResumePointIterator iter(resumePointsBegin());
    1095           1 :         MOZ_ASSERT(iter != resumePointsEnd());
    1096           1 :         iter++;
    1097           1 :         MOZ_ASSERT(iter == resumePointsEnd());
    1098             :     }
    1099             : #endif
    1100         393 : }
    1101             : 
    1102             : void
    1103         392 : MBasicBlock::clear()
    1104             : {
    1105         392 :     discardAllInstructions();
    1106         392 :     discardAllResumePoints();
    1107             : 
    1108             :     // Note: phis are disconnected from the rest of the graph, but are not
    1109             :     // removed entirely. If the block being removed is a loop header then
    1110             :     // IonBuilder may need to access these phis to more quickly converge on the
    1111             :     // possible types in the graph. See IonBuilder::analyzeNewLoopTypes.
    1112         392 :     discardAllPhiOperands();
    1113         392 : }
    1114             : 
    1115             : void
    1116        1272 : MBasicBlock::insertBefore(MInstruction* at, MInstruction* ins)
    1117             : {
    1118        1272 :     MOZ_ASSERT(at->block() == this);
    1119        1272 :     ins->setBlock(this);
    1120        1272 :     graph().allocDefinitionId(ins);
    1121        1272 :     instructions_.insertBefore(at, ins);
    1122        1272 :     ins->setTrackedSite(at->trackedSite());
    1123        1272 : }
    1124             : 
    1125             : void
    1126          32 : MBasicBlock::insertAfter(MInstruction* at, MInstruction* ins)
    1127             : {
    1128          32 :     MOZ_ASSERT(at->block() == this);
    1129          32 :     ins->setBlock(this);
    1130          32 :     graph().allocDefinitionId(ins);
    1131          32 :     instructions_.insertAfter(at, ins);
    1132          32 :     ins->setTrackedSite(at->trackedSite());
    1133          32 : }
    1134             : 
    1135             : void
    1136           0 : MBasicBlock::insertAtEnd(MInstruction* ins)
    1137             : {
    1138           0 :     if (hasLastIns())
    1139           0 :         insertBefore(lastIns(), ins);
    1140             :     else
    1141           0 :         add(ins);
    1142           0 : }
    1143             : 
    1144             : void
    1145       20304 : MBasicBlock::add(MInstruction* ins)
    1146             : {
    1147       20304 :     MOZ_ASSERT(!hasLastIns());
    1148       20304 :     ins->setBlock(this);
    1149       20304 :     graph().allocDefinitionId(ins);
    1150       20304 :     instructions_.pushBack(ins);
    1151       20304 :     ins->setTrackedSite(trackedSite_);
    1152       20304 : }
    1153             : 
    1154             : void
    1155        4111 : MBasicBlock::end(MControlInstruction* ins)
    1156             : {
    1157        4111 :     MOZ_ASSERT(!hasLastIns()); // Existing control instructions should be removed first.
    1158        4111 :     MOZ_ASSERT(ins);
    1159        4111 :     add(ins);
    1160        4111 : }
    1161             : 
    1162             : void
    1163        2728 : MBasicBlock::addPhi(MPhi* phi)
    1164             : {
    1165        2728 :     phis_.pushBack(phi);
    1166        2728 :     phi->setBlock(this);
    1167        2728 :     graph().allocDefinitionId(phi);
    1168        2728 : }
    1169             : 
    1170             : void
    1171        1952 : MBasicBlock::discardPhi(MPhi* phi)
    1172             : {
    1173        1952 :     MOZ_ASSERT(!phis_.empty());
    1174             : 
    1175        1952 :     phi->removeAllOperands();
    1176        1952 :     phi->setDiscarded();
    1177             : 
    1178        1952 :     phis_.remove(phi);
    1179             : 
    1180        1952 :     if (phis_.empty()) {
    1181         122 :         for (MBasicBlock* pred : predecessors_)
    1182          77 :             pred->clearSuccessorWithPhis();
    1183             :     }
    1184        1952 : }
    1185             : 
    1186             : void
    1187         115 : MBasicBlock::flagOperandsOfPrunedBranches(MInstruction* ins)
    1188             : {
    1189             :     // Find the previous resume point which would be used for bailing out.
    1190         115 :     MResumePoint* rp = nullptr;
    1191         764 :     for (MInstructionReverseIterator iter = rbegin(ins); iter != rend(); iter++) {
    1192         715 :         rp = iter->resumePoint();
    1193         715 :         if (rp)
    1194          66 :             break;
    1195             :     }
    1196             : 
    1197             :     // If none, take the entry resume point.
    1198         115 :     if (!rp)
    1199          49 :         rp = entryResumePoint();
    1200             : 
    1201             :     // The only blocks which do not have any entryResumePoint in Ion, are the
    1202             :     // SplitEdge blocks.  SplitEdge blocks only have a Goto instruction before
    1203             :     // Range Analysis phase.  In adjustInputs, we are manipulating instructions
    1204             :     // which have a TypePolicy.  So, as a Goto has no operand and no type
    1205             :     // policy, the entry resume point should exists.
    1206         115 :     MOZ_ASSERT(rp);
    1207             : 
    1208             :     // Flag all operand as being potentially used.
    1209         154 :     while (rp) {
    1210        2501 :         for (size_t i = 0, end = rp->numOperands(); i < end; i++)
    1211        2347 :             rp->getOperand(i)->setUseRemovedUnchecked();
    1212         154 :         rp = rp->caller();
    1213             :     }
    1214         115 : }
    1215             : 
    1216             : bool
    1217         669 : MBasicBlock::addPredecessor(TempAllocator& alloc, MBasicBlock* pred)
    1218             : {
    1219         669 :     return addPredecessorPopN(alloc, pred, 0);
    1220             : }
    1221             : 
    1222             : bool
    1223         669 : MBasicBlock::addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped)
    1224             : {
    1225         669 :     MOZ_ASSERT(pred);
    1226         669 :     MOZ_ASSERT(predecessors_.length() > 0);
    1227             : 
    1228             :     // Predecessors must be finished, and at the correct stack depth.
    1229         669 :     MOZ_ASSERT(pred->hasLastIns());
    1230         669 :     MOZ_ASSERT(pred->stackPosition_ == stackPosition_ + popped);
    1231             : 
    1232       10188 :     for (uint32_t i = 0, e = stackPosition_; i < e; ++i) {
    1233        9519 :         MDefinition* mine = getSlot(i);
    1234        9519 :         MDefinition* other = pred->getSlot(i);
    1235             : 
    1236        9519 :         if (mine != other) {
    1237             :             // If the current instruction is a phi, and it was created in this
    1238             :             // basic block, then we have already placed this phi and should
    1239             :             // instead append to its operands.
    1240        1312 :             if (mine->isPhi() && mine->block() == this) {
    1241         222 :                 MOZ_ASSERT(predecessors_.length());
    1242         222 :                 if (!mine->toPhi()->addInputSlow(other))
    1243           0 :                     return false;
    1244             :             } else {
    1245             :                 // Otherwise, create a new phi node.
    1246             :                 MPhi* phi;
    1247        1090 :                 if (mine->type() == other->type())
    1248         773 :                     phi = MPhi::New(alloc.fallible(), mine->type());
    1249             :                 else
    1250         317 :                     phi = MPhi::New(alloc.fallible());
    1251        1090 :                 if (!phi)
    1252           0 :                     return false;
    1253        1090 :                 addPhi(phi);
    1254             : 
    1255             :                 // Prime the phi for each predecessor, so input(x) comes from
    1256             :                 // predecessor(x).
    1257        1090 :                 if (!phi->reserveLength(predecessors_.length() + 1))
    1258           0 :                     return false;
    1259             : 
    1260        2228 :                 for (size_t j = 0, numPreds = predecessors_.length(); j < numPreds; ++j) {
    1261        1138 :                     MOZ_ASSERT(predecessors_[j]->getSlot(i) == mine);
    1262        1138 :                     phi->addInput(mine);
    1263             :                 }
    1264        1090 :                 phi->addInput(other);
    1265             : 
    1266        1090 :                 setSlot(i, phi);
    1267        1090 :                 if (entryResumePoint())
    1268        1090 :                     entryResumePoint()->replaceOperand(i, phi);
    1269             :             }
    1270             :         }
    1271             :     }
    1272             : 
    1273         669 :     return predecessors_.append(pred);
    1274             : }
    1275             : 
    1276             : void
    1277         161 : MBasicBlock::addPredecessorSameInputsAs(MBasicBlock* pred, MBasicBlock* existingPred)
    1278             : {
    1279         161 :     MOZ_ASSERT(pred);
    1280         161 :     MOZ_ASSERT(predecessors_.length() > 0);
    1281             : 
    1282             :     // Predecessors must be finished, and at the correct stack depth.
    1283         161 :     MOZ_ASSERT(pred->hasLastIns());
    1284         161 :     MOZ_ASSERT(!pred->successorWithPhis());
    1285             : 
    1286         322 :     AutoEnterOOMUnsafeRegion oomUnsafe;
    1287             : 
    1288         161 :     if (!phisEmpty()) {
    1289           2 :         size_t existingPosition = indexForPredecessor(existingPred);
    1290           4 :         for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
    1291           2 :             if (!iter->addInputSlow(iter->getOperand(existingPosition)))
    1292           0 :                 oomUnsafe.crash("MBasicBlock::addPredecessorAdjustPhis");
    1293             :         }
    1294             :     }
    1295             : 
    1296         161 :     if (!predecessors_.append(pred))
    1297           0 :         oomUnsafe.crash("MBasicBlock::addPredecessorAdjustPhis");
    1298         161 : }
    1299             : 
    1300             : bool
    1301         101 : MBasicBlock::addPredecessorWithoutPhis(MBasicBlock* pred)
    1302             : {
    1303             :     // Predecessors must be finished.
    1304         101 :     MOZ_ASSERT(pred && pred->hasLastIns());
    1305         101 :     return predecessors_.append(pred);
    1306             : }
    1307             : 
    1308             : bool
    1309        3592 : MBasicBlock::addImmediatelyDominatedBlock(MBasicBlock* child)
    1310             : {
    1311        3592 :     return immediatelyDominated_.append(child);
    1312             : }
    1313             : 
    1314             : void
    1315          50 : MBasicBlock::removeImmediatelyDominatedBlock(MBasicBlock* child)
    1316             : {
    1317          95 :     for (size_t i = 0; ; ++i) {
    1318          95 :         MOZ_ASSERT(i < immediatelyDominated_.length(),
    1319             :                    "Dominated block to remove not present");
    1320          95 :         if (immediatelyDominated_[i] == child) {
    1321          50 :             immediatelyDominated_[i] = immediatelyDominated_.back();
    1322          50 :             immediatelyDominated_.popBack();
    1323          50 :             return;
    1324             :         }
    1325             :     }
    1326             : }
    1327             : 
    1328             : void
    1329           0 : MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
    1330             : {
    1331             : #ifdef DEBUG
    1332           0 :     for (; use != end; use++) {
    1333           0 :         MOZ_ASSERT_IF(use->consumer()->isDefinition(),
    1334             :                       use->consumer()->toDefinition()->block()->id() < id());
    1335             :     }
    1336             : #endif
    1337           0 : }
    1338             : 
    1339             : AbortReason
    1340         117 : MBasicBlock::setBackedge(TempAllocator& alloc, MBasicBlock* pred)
    1341             : {
    1342             :     // Predecessors must be finished, and at the correct stack depth.
    1343         117 :     MOZ_ASSERT(hasLastIns());
    1344         117 :     MOZ_ASSERT(pred->hasLastIns());
    1345         117 :     MOZ_ASSERT(pred->stackDepth() == entryResumePoint()->stackDepth());
    1346             : 
    1347             :     // We must be a pending loop header
    1348         117 :     MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
    1349             : 
    1350         117 :     bool hadTypeChange = false;
    1351             : 
    1352             :     // Add exit definitions to each corresponding phi at the entry.
    1353         117 :     if (!inheritPhisFromBackedge(alloc, pred, &hadTypeChange))
    1354           0 :         return AbortReason::Alloc;
    1355             : 
    1356         117 :     if (hadTypeChange) {
    1357          11 :         for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++)
    1358          10 :             phi->removeOperand(phi->numOperands() - 1);
    1359           1 :         return AbortReason::Disable;
    1360             :     }
    1361             : 
    1362             :     // We are now a loop header proper
    1363         116 :     kind_ = LOOP_HEADER;
    1364             : 
    1365         116 :     if (!predecessors_.append(pred))
    1366           0 :         return AbortReason::Alloc;
    1367             : 
    1368         116 :     return AbortReason::NoAbort;
    1369             : }
    1370             : 
    1371             : bool
    1372           0 : MBasicBlock::setBackedgeWasm(MBasicBlock* pred)
    1373             : {
    1374             :     // Predecessors must be finished, and at the correct stack depth.
    1375           0 :     MOZ_ASSERT(hasLastIns());
    1376           0 :     MOZ_ASSERT(pred->hasLastIns());
    1377           0 :     MOZ_ASSERT(stackDepth() == pred->stackDepth());
    1378             : 
    1379             :     // We must be a pending loop header
    1380           0 :     MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
    1381             : 
    1382             :     // Add exit definitions to each corresponding phi at the entry.
    1383             :     // Note: Phis are inserted in the same order as the slots. (see
    1384             :     // MBasicBlock::New)
    1385           0 :     size_t slot = 0;
    1386           0 :     for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++, slot++) {
    1387           0 :         MPhi* entryDef = *phi;
    1388           0 :         MDefinition* exitDef = pred->getSlot(slot);
    1389             : 
    1390             :         // Assert that we already placed phis for each slot.
    1391           0 :         MOZ_ASSERT(entryDef->block() == this);
    1392             : 
    1393             :         // Assert that the phi already has the correct type.
    1394           0 :         MOZ_ASSERT(entryDef->type() == exitDef->type());
    1395           0 :         MOZ_ASSERT(entryDef->type() != MIRType::Value);
    1396             : 
    1397           0 :         if (entryDef == exitDef) {
    1398             :             // If the exit def is the same as the entry def, make a redundant
    1399             :             // phi. Since loop headers have exactly two incoming edges, we
    1400             :             // know that that's just the first input.
    1401             :             //
    1402             :             // Note that we eliminate later rather than now, to avoid any
    1403             :             // weirdness around pending continue edges which might still hold
    1404             :             // onto phis.
    1405           0 :             exitDef = entryDef->getOperand(0);
    1406             :         }
    1407             : 
    1408             :         // Phis always have room for 2 operands, so this can't fail.
    1409           0 :         MOZ_ASSERT(phi->numOperands() == 1);
    1410           0 :         entryDef->addInlineInput(exitDef);
    1411             : 
    1412           0 :         MOZ_ASSERT(slot < pred->stackDepth());
    1413           0 :         setSlot(slot, entryDef);
    1414             :     }
    1415             : 
    1416             :     // We are now a loop header proper
    1417           0 :     kind_ = LOOP_HEADER;
    1418             : 
    1419           0 :     return predecessors_.append(pred);
    1420             : }
    1421             : 
    1422             : void
    1423           0 : MBasicBlock::clearLoopHeader()
    1424             : {
    1425           0 :     MOZ_ASSERT(isLoopHeader());
    1426           0 :     kind_ = NORMAL;
    1427           0 : }
    1428             : 
    1429             : void
    1430           0 : MBasicBlock::setLoopHeader(MBasicBlock* newBackedge)
    1431             : {
    1432           0 :     MOZ_ASSERT(!isLoopHeader());
    1433           0 :     kind_ = LOOP_HEADER;
    1434             : 
    1435           0 :     size_t numPreds = numPredecessors();
    1436           0 :     MOZ_ASSERT(numPreds != 0);
    1437             : 
    1438           0 :     size_t lastIndex = numPreds - 1;
    1439           0 :     size_t oldIndex = 0;
    1440           0 :     for (; ; ++oldIndex) {
    1441           0 :         MOZ_ASSERT(oldIndex < numPreds);
    1442           0 :         MBasicBlock* pred = getPredecessor(oldIndex);
    1443           0 :         if (pred == newBackedge)
    1444           0 :             break;
    1445           0 :     }
    1446             : 
    1447             :     // Set the loop backedge to be the last element in predecessors_.
    1448           0 :     Swap(predecessors_[oldIndex], predecessors_[lastIndex]);
    1449             : 
    1450             :     // If we have phis, reorder their operands accordingly.
    1451           0 :     if (!phisEmpty()) {
    1452           0 :         getPredecessor(oldIndex)->setSuccessorWithPhis(this, oldIndex);
    1453           0 :         getPredecessor(lastIndex)->setSuccessorWithPhis(this, lastIndex);
    1454           0 :         for (MPhiIterator iter(phisBegin()), end(phisEnd()); iter != end; ++iter) {
    1455           0 :             MPhi* phi = *iter;
    1456           0 :             MDefinition* last = phi->getOperand(oldIndex);
    1457           0 :             MDefinition* old = phi->getOperand(lastIndex);
    1458           0 :             phi->replaceOperand(oldIndex, old);
    1459           0 :             phi->replaceOperand(lastIndex, last);
    1460             :         }
    1461             :     }
    1462             : 
    1463           0 :     MOZ_ASSERT(newBackedge->loopHeaderOfBackedge() == this);
    1464           0 :     MOZ_ASSERT(backedge() == newBackedge);
    1465           0 : }
    1466             : 
    1467             : size_t
    1468      109839 : MBasicBlock::numSuccessors() const
    1469             : {
    1470      109839 :     MOZ_ASSERT(lastIns());
    1471      109834 :     return lastIns()->numSuccessors();
    1472             : }
    1473             : 
    1474             : MBasicBlock*
    1475       58731 : MBasicBlock::getSuccessor(size_t index) const
    1476             : {
    1477       58731 :     MOZ_ASSERT(lastIns());
    1478       58729 :     return lastIns()->getSuccessor(index);
    1479             : }
    1480             : 
    1481             : size_t
    1482         122 : MBasicBlock::getSuccessorIndex(MBasicBlock* block) const
    1483             : {
    1484         122 :     MOZ_ASSERT(lastIns());
    1485         239 :     for (size_t i = 0; i < numSuccessors(); i++) {
    1486         239 :         if (getSuccessor(i) == block)
    1487         244 :             return i;
    1488             :     }
    1489           0 :     MOZ_CRASH("Invalid successor");
    1490             : }
    1491             : 
    1492             : size_t
    1493         395 : MBasicBlock::getPredecessorIndex(MBasicBlock* block) const
    1494             : {
    1495         543 :     for (size_t i = 0, e = numPredecessors(); i < e; ++i) {
    1496         543 :         if (getPredecessor(i) == block)
    1497         790 :             return i;
    1498             :     }
    1499           0 :     MOZ_CRASH("Invalid predecessor");
    1500             : }
    1501             : 
    1502             : void
    1503          14 : MBasicBlock::replaceSuccessor(size_t pos, MBasicBlock* split)
    1504             : {
    1505          14 :     MOZ_ASSERT(lastIns());
    1506             : 
    1507             :     // Note, during split-critical-edges, successors-with-phis is not yet set.
    1508             :     // During PAA, this case is handled before we enter.
    1509          14 :     MOZ_ASSERT_IF(successorWithPhis_, successorWithPhis_ != getSuccessor(pos));
    1510             : 
    1511          14 :     lastIns()->replaceSuccessor(pos, split);
    1512          14 : }
    1513             : 
    1514             : void
    1515          14 : MBasicBlock::replacePredecessor(MBasicBlock* old, MBasicBlock* split)
    1516             : {
    1517          20 :     for (size_t i = 0; i < numPredecessors(); i++) {
    1518          20 :         if (getPredecessor(i) == old) {
    1519          14 :             predecessors_[i] = split;
    1520             : 
    1521             : #ifdef DEBUG
    1522             :             // The same block should not appear twice in the predecessor list.
    1523          36 :             for (size_t j = i; j < numPredecessors(); j++)
    1524          22 :                 MOZ_ASSERT(predecessors_[j] != old);
    1525             : #endif
    1526             : 
    1527          28 :             return;
    1528             :         }
    1529             :     }
    1530             : 
    1531           0 :     MOZ_CRASH("predecessor was not found");
    1532             : }
    1533             : 
    1534             : void
    1535         382 : MBasicBlock::clearDominatorInfo()
    1536             : {
    1537         382 :     setImmediateDominator(nullptr);
    1538         382 :     immediatelyDominated_.clear();
    1539         382 :     numDominated_ = 0;
    1540         382 : }
    1541             : 
    1542             : void
    1543         276 : MBasicBlock::removePredecessorWithoutPhiOperands(MBasicBlock* pred, size_t predIndex)
    1544             : {
    1545             :     // If we're removing the last backedge, this is no longer a loop.
    1546         276 :     if (isLoopHeader() && hasUniqueBackedge() && backedge() == pred)
    1547           0 :         clearLoopHeader();
    1548             : 
    1549             :     // Adjust phis.  Note that this can leave redundant phis behind.
    1550             :     // Don't adjust successorWithPhis() if we haven't constructed this
    1551             :     // information yet.
    1552         276 :     if (pred->successorWithPhis()) {
    1553          11 :         MOZ_ASSERT(pred->positionInPhiSuccessor() == predIndex);
    1554          11 :         pred->clearSuccessorWithPhis();
    1555          23 :         for (size_t j = predIndex+1; j < numPredecessors(); j++)
    1556          12 :             getPredecessor(j)->setSuccessorWithPhis(this, j - 1);
    1557             :     }
    1558             : 
    1559             :     // Remove from pred list.
    1560         276 :     predecessors_.erase(predecessors_.begin() + predIndex);
    1561         276 : }
    1562             : 
    1563             : void
    1564         205 : MBasicBlock::removePredecessor(MBasicBlock* pred)
    1565             : {
    1566         205 :     size_t predIndex = getPredecessorIndex(pred);
    1567             : 
    1568             :     // Remove the phi operands.
    1569         315 :     for (MPhiIterator iter(phisBegin()), end(phisEnd()); iter != end; ++iter)
    1570         110 :         iter->removeOperand(predIndex);
    1571             : 
    1572             :     // Now we can call the underlying function, which expects that phi
    1573             :     // operands have been removed.
    1574         205 :     removePredecessorWithoutPhiOperands(pred, predIndex);
    1575         205 : }
    1576             : 
    1577             : void
    1578           0 : MBasicBlock::inheritPhis(MBasicBlock* header)
    1579             : {
    1580           0 :     MResumePoint* headerRp = header->entryResumePoint();
    1581           0 :     size_t stackDepth = headerRp->stackDepth();
    1582           0 :     for (size_t slot = 0; slot < stackDepth; slot++) {
    1583           0 :         MDefinition* exitDef = getSlot(slot);
    1584           0 :         MDefinition* loopDef = headerRp->getOperand(slot);
    1585           0 :         if (loopDef->block() != header) {
    1586           0 :             MOZ_ASSERT(loopDef->block()->id() < header->id());
    1587           0 :             MOZ_ASSERT(loopDef == exitDef);
    1588           0 :             continue;
    1589             :         }
    1590             : 
    1591             :         // Phis are allocated by NewPendingLoopHeader.
    1592           0 :         MPhi* phi = loopDef->toPhi();
    1593           0 :         MOZ_ASSERT(phi->numOperands() == 2);
    1594             : 
    1595             :         // The entry definition is always the leftmost input to the phi.
    1596           0 :         MDefinition* entryDef = phi->getOperand(0);
    1597             : 
    1598           0 :         if (entryDef != exitDef)
    1599           0 :             continue;
    1600             : 
    1601             :         // If the entryDef is the same as exitDef, then we must propagate the
    1602             :         // phi down to this successor. This chance was missed as part of
    1603             :         // setBackedge() because exits are not captured in resume points.
    1604           0 :         setSlot(slot, phi);
    1605             :     }
    1606           0 : }
    1607             : 
    1608             : bool
    1609         117 : MBasicBlock::inheritPhisFromBackedge(TempAllocator& alloc, MBasicBlock* backedge, bool* hadTypeChange)
    1610             : {
    1611             :     // We must be a pending loop header
    1612         117 :     MOZ_ASSERT(kind_ == PENDING_LOOP_HEADER);
    1613             : 
    1614         117 :     size_t stackDepth = entryResumePoint()->stackDepth();
    1615        1636 :     for (size_t slot = 0; slot < stackDepth; slot++) {
    1616             :         // Get the value stack-slot of the back edge.
    1617        1519 :         MDefinition* exitDef = backedge->getSlot(slot);
    1618             : 
    1619             :         // Get the value of the loop header.
    1620        1519 :         MDefinition* loopDef = entryResumePoint()->getOperand(slot);
    1621        1519 :         if (loopDef->block() != this) {
    1622             :             // If we are finishing a pending loop header, then we need to ensure
    1623             :             // that all operands are phis. This is usualy the case, except for
    1624             :             // object/arrays build with generators, in which case we share the
    1625             :             // same allocations across all blocks.
    1626           0 :             MOZ_ASSERT(loopDef->block()->id() < id());
    1627           0 :             MOZ_ASSERT(loopDef == exitDef);
    1628           0 :             continue;
    1629             :         }
    1630             : 
    1631             :         // Phis are allocated by NewPendingLoopHeader.
    1632        1519 :         MPhi* entryDef = loopDef->toPhi();
    1633        1519 :         MOZ_ASSERT(entryDef->block() == this);
    1634             : 
    1635        1519 :         if (entryDef == exitDef) {
    1636             :             // If the exit def is the same as the entry def, make a redundant
    1637             :             // phi. Since loop headers have exactly two incoming edges, we
    1638             :             // know that that's just the first input.
    1639             :             //
    1640             :             // Note that we eliminate later rather than now, to avoid any
    1641             :             // weirdness around pending continue edges which might still hold
    1642             :             // onto phis.
    1643        1157 :             exitDef = entryDef->getOperand(0);
    1644             :         }
    1645             : 
    1646        1519 :         bool typeChange = false;
    1647             : 
    1648        1519 :         if (!entryDef->addInputSlow(exitDef))
    1649           0 :             return false;
    1650        1519 :         if (!entryDef->checkForTypeChange(alloc, exitDef, &typeChange))
    1651           0 :             return false;
    1652        1519 :         *hadTypeChange |= typeChange;
    1653        1519 :         setSlot(slot, entryDef);
    1654             :     }
    1655             : 
    1656         117 :     return true;
    1657             : }
    1658             : 
    1659             : bool
    1660        4762 : MBasicBlock::specializePhis(TempAllocator& alloc)
    1661             : {
    1662        4762 :     if (specialized_)
    1663        1089 :         return true;
    1664             : 
    1665        3673 :     specialized_ = true;
    1666        6308 :     for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
    1667        2635 :         MPhi* phi = *iter;
    1668        2635 :         if (!phi->specializeType(alloc))
    1669           0 :             return false;
    1670             :     }
    1671        3673 :     return true;
    1672             : }
    1673             : 
    1674             : MTest*
    1675         456 : MBasicBlock::immediateDominatorBranch(BranchDirection* pdirection)
    1676             : {
    1677         456 :     *pdirection = FALSE_BRANCH;
    1678             : 
    1679         456 :     if (numPredecessors() != 1)
    1680          96 :         return nullptr;
    1681             : 
    1682         360 :     MBasicBlock* dom = immediateDominator();
    1683         360 :     if (dom != getPredecessor(0))
    1684           0 :         return nullptr;
    1685             : 
    1686             :     // Look for a trailing MTest branching to this block.
    1687         360 :     MInstruction* ins = dom->lastIns();
    1688         360 :     if (ins->isTest()) {
    1689         229 :         MTest* test = ins->toTest();
    1690             : 
    1691         229 :         MOZ_ASSERT(test->ifTrue() == this || test->ifFalse() == this);
    1692         229 :         if (test->ifTrue() == this && test->ifFalse() == this)
    1693           0 :             return nullptr;
    1694             : 
    1695         229 :         *pdirection = (test->ifTrue() == this) ? TRUE_BRANCH : FALSE_BRANCH;
    1696         229 :         return test;
    1697             :     }
    1698             : 
    1699         131 :     return nullptr;
    1700             : }
    1701             : 
    1702          33 : MBasicBlock::BackupPoint::BackupPoint(MBasicBlock* current)
    1703             :   : current_(current),
    1704          95 :     lastIns_(current->hasAnyIns() ? *current->rbegin() : nullptr),
    1705          33 :     stackPosition_(current->stackDepth()),
    1706             :     slots_()
    1707             : #ifdef DEBUG
    1708          67 :   , lastPhi_(!current->phisEmpty() ? *current->phis_.rbegin() : nullptr),
    1709          33 :     predecessorsCheckSum_(computePredecessorsCheckSum(current)),
    1710          33 :     instructionsCheckSum_(computeInstructionsCheckSum(current)),
    1711          33 :     id_(current->id()),
    1712          33 :     callerResumePoint_(current->callerResumePoint()),
    1713         300 :     entryResumePoint_(current->entryResumePoint())
    1714             : #endif
    1715             : {
    1716             :     // The block is not yet jumping into a block of an inlined function yet.
    1717          33 :     MOZ_ASSERT(current->outerResumePoint_ == nullptr);
    1718          33 : }
    1719             : 
    1720             : bool
    1721          33 : MBasicBlock::BackupPoint::init(TempAllocator& alloc)
    1722             : {
    1723          33 :     if (!slots_.init(alloc, stackPosition_))
    1724           0 :         return false;
    1725         406 :     for (size_t i = 0, e = stackPosition_; i < e; ++i)
    1726         373 :         slots_[i] = current_->slots_[i];
    1727          33 :     return true;
    1728             : }
    1729             : 
    1730             : #ifdef DEBUG
    1731             : uintptr_t
    1732          33 : MBasicBlock::BackupPoint::computePredecessorsCheckSum(MBasicBlock* block)
    1733             : {
    1734          33 :     uintptr_t hash = 0;
    1735          65 :     for (size_t i = 0; i < block->numPredecessors(); i++) {
    1736          32 :         MBasicBlock* pred = block->getPredecessor(i);
    1737          32 :         uintptr_t data = reinterpret_cast<uintptr_t>(pred);
    1738          32 :         hash = data + (hash << 6) + (hash << 16) - hash;
    1739             :     }
    1740          33 :     return hash;
    1741             : }
    1742             : 
    1743             : HashNumber
    1744          33 : MBasicBlock::BackupPoint::computeInstructionsCheckSum(MBasicBlock* block)
    1745             : {
    1746          33 :     HashNumber h = 0;
    1747          33 :     MOZ_ASSERT_IF(lastIns_, lastIns_->block() == block);
    1748         204 :     for (MInstructionIterator ins = block->begin(); ins != block->end(); ++ins) {
    1749         171 :         h += ins->valueHash();
    1750         171 :         h += h << 10;
    1751         171 :         h ^= h >> 6;
    1752             :     }
    1753          33 :     return h;
    1754             : }
    1755             : #endif
    1756             : 
    1757             : MBasicBlock*
    1758           0 : MBasicBlock::BackupPoint::restore()
    1759             : {
    1760             :     // No extra Phi got added.
    1761           0 :     MOZ_ASSERT((!current_->phisEmpty() ? *current_->phis_.rbegin() : nullptr) == lastPhi_);
    1762             : 
    1763           0 :     MOZ_ASSERT_IF(lastIns_, lastIns_->block() == current_);
    1764           0 :     MOZ_ASSERT_IF(lastIns_, !lastIns_->isDiscarded());
    1765             : 
    1766           0 :     if (!current_->graph().removeSuccessorBlocks(current_))
    1767           0 :         return nullptr;
    1768             : 
    1769           0 :     MInstructionIterator lastIns(lastIns_ ? ++(current_->begin(lastIns_)) : current_->begin());
    1770           0 :     current_->discardAllInstructionsStartingAt(lastIns);
    1771           0 :     current_->clearOuterResumePoint();
    1772             : 
    1773           0 :     MOZ_ASSERT(current_->slots_.length() >= stackPosition_);
    1774           0 :     if (current_->stackPosition_ != stackPosition_)
    1775           0 :         current_->setStackDepth(stackPosition_);
    1776           0 :     for (size_t i = 0, e = stackPosition_; i < e; ++i)
    1777           0 :         current_->slots_[i] = slots_[i];
    1778             : 
    1779           0 :     MOZ_ASSERT(current_->id() == id_);
    1780           0 :     MOZ_ASSERT(predecessorsCheckSum_ == computePredecessorsCheckSum(current_));
    1781           0 :     MOZ_ASSERT(instructionsCheckSum_ == computeInstructionsCheckSum(current_));
    1782           0 :     MOZ_ASSERT(current_->callerResumePoint() == callerResumePoint_);
    1783           0 :     MOZ_ASSERT(current_->entryResumePoint() == entryResumePoint_);
    1784             : 
    1785           0 :     return current_;
    1786             : }
    1787             : 
    1788             : void
    1789           0 : MBasicBlock::dumpStack(GenericPrinter& out)
    1790             : {
    1791             : #ifdef DEBUG
    1792           0 :     out.printf(" %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next");
    1793           0 :     out.printf("-------------------------------------------\n");
    1794           0 :     for (uint32_t i = 0; i < stackPosition_; i++) {
    1795           0 :         out.printf(" %-3d", i);
    1796           0 :         out.printf(" %-16p\n", (void*)slots_[i]);
    1797             :     }
    1798             : #endif
    1799           0 : }
    1800             : 
    1801             : void
    1802           0 : MBasicBlock::dumpStack()
    1803             : {
    1804           0 :     Fprinter out(stderr);
    1805           0 :     dumpStack(out);
    1806           0 :     out.finish();
    1807           0 : }
    1808             : 
    1809             : void
    1810           0 : MIRGraph::dump(GenericPrinter& out)
    1811             : {
    1812             : #ifdef DEBUG
    1813           0 :     for (MBasicBlockIterator iter(begin()); iter != end(); iter++) {
    1814           0 :         iter->dump(out);
    1815           0 :         out.printf("\n");
    1816             :     }
    1817             : #endif
    1818           0 : }
    1819             : 
    1820             : void
    1821           0 : MIRGraph::dump()
    1822             : {
    1823           0 :     Fprinter out(stderr);
    1824           0 :     dump(out);
    1825           0 :     out.finish();
    1826           0 : }
    1827             : 
    1828             : void
    1829           0 : MBasicBlock::dump(GenericPrinter& out)
    1830             : {
    1831             : #ifdef DEBUG
    1832           0 :     out.printf("block%u:%s%s%s\n", id(),
    1833           0 :                isLoopHeader() ? " (loop header)" : "",
    1834           0 :                unreachable() ? " (unreachable)" : "",
    1835           0 :                isMarked() ? " (marked)" : "");
    1836           0 :     if (MResumePoint* resume = entryResumePoint())
    1837           0 :         resume->dump(out);
    1838           0 :     for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++)
    1839           0 :         iter->dump(out);
    1840           0 :     for (MInstructionIterator iter(begin()); iter != end(); iter++)
    1841           0 :         iter->dump(out);
    1842             : #endif
    1843           0 : }
    1844             : 
    1845             : void
    1846           0 : MBasicBlock::dump()
    1847             : {
    1848           0 :     Fprinter out(stderr);
    1849           0 :     dump(out);
    1850           0 :     out.finish();
    1851           0 : }

Generated by: LCOV version 1.13