Home | History | Annotate | Download | only in crankshaft
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/crankshaft/hydrogen-removable-simulates.h"
      6 
      7 #include "src/crankshaft/hydrogen-flow-engine.h"
      8 #include "src/crankshaft/hydrogen-instructions.h"
      9 #include "src/objects-inl.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 class State : public ZoneObject {
     15  public:
     16   explicit State(Zone* zone)
     17       : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
     18 
     19   State* Process(HInstruction* instr, Zone* zone) {
     20     if (FLAG_trace_removable_simulates) {
     21       PrintF("[%s with state %p in B%d: #%d %s]\n",
     22              mode_ == NORMAL ? "processing" : "collecting",
     23              reinterpret_cast<void*>(this), instr->block()->block_id(),
     24              instr->id(), instr->Mnemonic());
     25     }
     26     // Forward-merge "trains" of simulates after an instruction with observable
     27     // side effects to keep live ranges short.
     28     if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) {
     29       if (instr->IsSimulate()) {
     30         HSimulate* current_simulate = HSimulate::cast(instr);
     31         if (current_simulate->is_candidate_for_removal() &&
     32             !current_simulate->ast_id().IsNone()) {
     33           Remember(current_simulate);
     34           return this;
     35         }
     36       }
     37       FlushSimulates();
     38       mode_ = NORMAL;
     39     }
     40     // Ensure there's a non-foldable HSimulate before an HEnterInlined to avoid
     41     // folding across HEnterInlined.
     42     DCHECK(!(instr->IsEnterInlined() &&
     43              HSimulate::cast(instr->previous())->is_candidate_for_removal()));
     44     if (instr->IsLeaveInlined() || instr->IsReturn()) {
     45       // Never fold simulates from inlined environments into simulates in the
     46       // outer environment. Simply remove all accumulated simulates without
     47       // merging. This is safe because simulates after instructions with side
     48       // effects are never added to the merge list. The same reasoning holds for
     49       // return instructions.
     50       RemoveSimulates();
     51       return this;
     52     }
     53     if (instr->IsControlInstruction()) {
     54       // Merge the accumulated simulates at the end of the block.
     55       FlushSimulates();
     56       return this;
     57     }
     58     if (instr->IsCapturedObject()) {
     59       // Do not merge simulates across captured objects - captured objects
     60       // change environments during environment replay, and such changes
     61       // would not be reflected in the simulate.
     62       FlushSimulates();
     63       return this;
     64     }
     65     // Skip the non-simulates and the first simulate.
     66     if (!instr->IsSimulate()) return this;
     67     if (first_) {
     68       first_ = false;
     69       return this;
     70     }
     71     HSimulate* current_simulate = HSimulate::cast(instr);
     72     if (!current_simulate->is_candidate_for_removal()) {
     73       Remember(current_simulate);
     74       FlushSimulates();
     75     } else if (current_simulate->ast_id().IsNone()) {
     76       DCHECK(current_simulate->next()->IsEnterInlined());
     77       FlushSimulates();
     78     } else if (current_simulate->previous()->HasObservableSideEffects()) {
     79       Remember(current_simulate);
     80       mode_ = COLLECT_CONSECUTIVE_SIMULATES;
     81     } else {
     82       Remember(current_simulate);
     83     }
     84 
     85     return this;
     86   }
     87 
     88   static State* Merge(State* succ_state,
     89                       HBasicBlock* succ_block,
     90                       State* pred_state,
     91                       HBasicBlock* pred_block,
     92                       Zone* zone) {
     93     return (succ_state == NULL)
     94         ? pred_state->Copy(succ_block, pred_block, zone)
     95         : succ_state->Merge(succ_block, pred_state, pred_block, zone);
     96   }
     97 
     98   static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
     99     if (FLAG_trace_removable_simulates) {
    100       PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state),
    101              block->block_id());
    102     }
    103     // For our current local analysis, we should not remember simulates across
    104     // block boundaries.
    105     DCHECK(!state->HasRememberedSimulates());
    106     // Nasty heuristic: Never remove the first simulate in a block. This
    107     // just so happens to have a beneficial effect on register allocation.
    108     state->first_ = true;
    109     return state;
    110   }
    111 
    112  private:
    113   explicit State(const State& other)
    114       : zone_(other.zone_),
    115         mergelist_(other.mergelist_, other.zone_),
    116         first_(other.first_),
    117         mode_(other.mode_) { }
    118 
    119   enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
    120 
    121   bool HasRememberedSimulates() const { return !mergelist_.is_empty(); }
    122 
    123   void Remember(HSimulate* sim) {
    124     mergelist_.Add(sim, zone_);
    125   }
    126 
    127   void FlushSimulates() {
    128     if (HasRememberedSimulates()) {
    129       mergelist_.RemoveLast()->MergeWith(&mergelist_);
    130     }
    131   }
    132 
    133   void RemoveSimulates() {
    134     while (HasRememberedSimulates()) {
    135       mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
    136     }
    137   }
    138 
    139   State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) {
    140     State* copy = new(zone) State(*this);
    141     if (FLAG_trace_removable_simulates) {
    142       PrintF("[copy state %p from B%d to new state %p for B%d]\n",
    143              reinterpret_cast<void*>(this), pred_block->block_id(),
    144              reinterpret_cast<void*>(copy), succ_block->block_id());
    145     }
    146     return copy;
    147   }
    148 
    149   State* Merge(HBasicBlock* succ_block,
    150                State* pred_state,
    151                HBasicBlock* pred_block,
    152                Zone* zone) {
    153     // For our current local analysis, we should not remember simulates across
    154     // block boundaries.
    155     DCHECK(!pred_state->HasRememberedSimulates());
    156     DCHECK(!HasRememberedSimulates());
    157     if (FLAG_trace_removable_simulates) {
    158       PrintF("[merge state %p from B%d into %p for B%d]\n",
    159              reinterpret_cast<void*>(pred_state), pred_block->block_id(),
    160              reinterpret_cast<void*>(this), succ_block->block_id());
    161     }
    162     return this;
    163   }
    164 
    165   Zone* zone_;
    166   ZoneList<HSimulate*> mergelist_;
    167   bool first_;
    168   Mode mode_;
    169 };
    170 
    171 
    172 // We don't use effects here.
    173 class Effects : public ZoneObject {
    174  public:
    175   explicit Effects(Zone* zone) { }
    176   bool Disabled() { return true; }
    177   void Process(HInstruction* instr, Zone* zone) { }
    178   void Apply(State* state) { }
    179   void Union(Effects* that, Zone* zone) { }
    180 };
    181 
    182 
    183 void HMergeRemovableSimulatesPhase::Run() {
    184   HFlowEngine<State, Effects> engine(graph(), zone());
    185   State* state = new(zone()) State(zone());
    186   engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
    187 }
    188 
    189 }  // namespace internal
    190 }  // namespace v8
    191